Compare commits
2 Commits
e38bf07ef2
...
cb12a8f1cf
| Author | SHA1 | Date | |
|---|---|---|---|
| cb12a8f1cf | |||
| c1255bdb81 |
@@ -124,183 +124,12 @@
|
||||
- name: Show data/ contents after update (should match before)
|
||||
debug:
|
||||
msg: "{{ data_files_after.stdout_lines }}"
|
||||
|
||||
# ── 7. Restart WMT service ────────────────────────────────────────────
|
||||
- name: Restart WMT systemd service
|
||||
|
||||
# ── 9. Reboot ─────────────────────────────────────────────────────────
|
||||
- name: Reboot host to apply all changes
|
||||
become: true
|
||||
systemd:
|
||||
name: wmt
|
||||
state: restarted
|
||||
enabled: true
|
||||
register: service_result
|
||||
ignore_errors: true
|
||||
|
||||
- name: Show service state
|
||||
debug:
|
||||
msg: "WMT service state: {{ service_result.status.ActiveState | default('unknown') }}"
|
||||
when: service_result is not failed
|
||||
|
||||
- name: Warn if service restart failed
|
||||
debug:
|
||||
msg: "WARNING: wmt service restart failed – the device may need a manual reboot."
|
||||
when: service_result is failed
|
||||
|
||||
vars:
|
||||
wmt_dir: /home/pi/Desktop/WMT
|
||||
tmp_zip: /tmp/wmt_update.zip
|
||||
# Controller address – override on CLI with -e "server_url=http://..."
|
||||
server_url: "http://{{ hostvars[inventory_hostname]['ansible_host'] | default(ansible_host) | regex_replace('\\d+\\.\\d+$', '10.76.157.1') }}"
|
||||
|
||||
tasks:
|
||||
|
||||
# ── 0. Resolve server URL ─────────────────────────────────────────────
|
||||
# The monitoring server address is read from the device's own config.txt
|
||||
# so we don't have to hard-code it here.
|
||||
- name: Read server_host from WMT config.txt
|
||||
shell: |
|
||||
grep -E '^\s*server_host\s*=' {{ wmt_dir }}/data/config.txt 2>/dev/null \
|
||||
| head -1 | awk -F'=' '{print $2}' | tr -d ' \r\n'
|
||||
register: cfg_server_host
|
||||
changed_when: false
|
||||
ignore_errors: true
|
||||
|
||||
- name: Read server_port from WMT config.txt
|
||||
shell: |
|
||||
grep -E '^\s*server_port\s*=' {{ wmt_dir }}/data/config.txt 2>/dev/null \
|
||||
| head -1 | awk -F'=' '{print $2}' | tr -d ' \r\n'
|
||||
register: cfg_server_port
|
||||
changed_when: false
|
||||
ignore_errors: true
|
||||
|
||||
- name: Set monitoring server base URL
|
||||
set_fact:
|
||||
monitoring_base: "http://{{ cfg_server_host.stdout | default('rpi-ansible') }}:{{ cfg_server_port.stdout | default('5000') }}"
|
||||
|
||||
- name: Show resolved server URL
|
||||
debug:
|
||||
msg: "Monitoring server: {{ monitoring_base }}"
|
||||
|
||||
# ── 1. Check latest version on server ────────────────────────────────
|
||||
- name: Query latest WMT version from monitoring server
|
||||
uri:
|
||||
url: "{{ monitoring_base }}/api/wmt/client/version"
|
||||
method: GET
|
||||
return_content: true
|
||||
timeout: 15
|
||||
register: version_response
|
||||
ignore_errors: true
|
||||
|
||||
- name: Show server version info
|
||||
debug:
|
||||
msg: "Server release: v{{ version_response.json.version | default('unknown') }} ({{ version_response.json.filename | default('n/a') }})"
|
||||
when: version_response is not failed
|
||||
|
||||
- name: Fail if server version endpoint unreachable
|
||||
fail:
|
||||
msg: "Cannot reach {{ monitoring_base }}/api/wmt/client/version – is the server running?"
|
||||
when: version_response is failed
|
||||
|
||||
# ── 2. Get current local version ─────────────────────────────────────
|
||||
- name: Read first line of local app.py
|
||||
shell: head -1 {{ wmt_dir }}/app.py 2>/dev/null || echo "unknown"
|
||||
register: local_first_line
|
||||
changed_when: false
|
||||
|
||||
- name: Extract local version number
|
||||
set_fact:
|
||||
local_version: "{{ local_first_line.stdout | regex_search('version\\s+([\\d.]+)', '\\1') | first | default('0') }}"
|
||||
|
||||
- name: Show local version
|
||||
debug:
|
||||
msg: "Local version: {{ local_version }} | Server version: {{ version_response.json.version }}"
|
||||
|
||||
# ── 3. Ensure WMT directory exists ───────────────────────────────────
|
||||
- name: Ensure WMT directory exists
|
||||
file:
|
||||
path: "{{ wmt_dir }}"
|
||||
state: directory
|
||||
owner: pi
|
||||
group: pi
|
||||
mode: '0755'
|
||||
|
||||
# ── 4. Download release zip ───────────────────────────────────────────
|
||||
- name: Download WMT release zip from monitoring server
|
||||
get_url:
|
||||
url: "{{ monitoring_base }}/api/wmt/client/download"
|
||||
dest: "{{ tmp_zip }}"
|
||||
force: true
|
||||
timeout: 120
|
||||
mode: '0644'
|
||||
|
||||
# ── 5. Back up current app.py ─────────────────────────────────────────
|
||||
- name: Back up current app.py
|
||||
copy:
|
||||
src: "{{ wmt_dir }}/app.py"
|
||||
dest: "{{ wmt_dir }}/app.py.bak.{{ local_version }}"
|
||||
remote_src: true
|
||||
owner: pi
|
||||
group: pi
|
||||
mode: preserve
|
||||
ignore_errors: true
|
||||
|
||||
# ── 6. Extract zip – skip data/ directory ─────────────────────────────
|
||||
- name: Extract WMT release zip (preserving data/ directory)
|
||||
shell: |
|
||||
cd {{ wmt_dir }}
|
||||
python3 - <<'EOF'
|
||||
import zipfile, os, sys
|
||||
zip_path = "{{ tmp_zip }}"
|
||||
dest = "{{ wmt_dir }}"
|
||||
skipped = 0
|
||||
extracted = 0
|
||||
with zipfile.ZipFile(zip_path, 'r') as zf:
|
||||
for member in zf.infolist():
|
||||
p = member.filename.replace('\\', '/')
|
||||
if p.startswith('data/') or p == 'data':
|
||||
skipped += 1
|
||||
continue
|
||||
zf.extract(member, dest)
|
||||
extracted += 1
|
||||
print(f"Extracted {extracted} files, skipped {skipped} data/ entries")
|
||||
EOF
|
||||
register: extract_result
|
||||
changed_when: true
|
||||
|
||||
- name: Show extraction result
|
||||
debug:
|
||||
msg: "{{ extract_result.stdout }}"
|
||||
|
||||
# ── 7. Fix ownership ──────────────────────────────────────────────────
|
||||
- name: Set correct ownership on WMT directory
|
||||
become: true
|
||||
file:
|
||||
path: "{{ wmt_dir }}"
|
||||
owner: pi
|
||||
group: pi
|
||||
recurse: true
|
||||
|
||||
# ── 8. Clean up temp zip ──────────────────────────────────────────────
|
||||
- name: Remove temporary zip file
|
||||
file:
|
||||
path: "{{ tmp_zip }}"
|
||||
state: absent
|
||||
|
||||
# ── 9. Restart WMT service ────────────────────────────────────────────
|
||||
- name: Restart WMT systemd service
|
||||
become: true
|
||||
systemd:
|
||||
name: wmt
|
||||
state: restarted
|
||||
enabled: true
|
||||
register: service_result
|
||||
ignore_errors: true
|
||||
|
||||
- name: Show service restart result
|
||||
debug:
|
||||
msg: "Service state: {{ service_result.status.ActiveState | default('unknown') }}"
|
||||
when: service_result is not failed
|
||||
|
||||
- name: Warn if service restart failed
|
||||
debug:
|
||||
msg: "WARNING: wmt service restart failed – the device may need a manual reboot."
|
||||
when: service_result is failed
|
||||
reboot:
|
||||
msg: "Rebooting after WMT code update "
|
||||
reboot_timeout: 180
|
||||
pre_reboot_delay: 3
|
||||
post_reboot_delay: 15
|
||||
+2
-2
@@ -98,8 +98,8 @@ def get_device_config(mac_address):
|
||||
_, device_ts, latest_ts = _latest_config_ts(session, mac)
|
||||
|
||||
payload = {
|
||||
# Global settings
|
||||
'chrome_url': global_cfg.chrome_url,
|
||||
# Global settings (device custom_chrome_url overrides global chrome_url if set)
|
||||
'chrome_url': (device.custom_chrome_url if device and device.custom_chrome_url else global_cfg.chrome_url),
|
||||
'chrome_local_url': global_cfg.chrome_local_url or '',
|
||||
'chrome_insecure_origin': global_cfg.chrome_insecure_origin,
|
||||
'card_api_base_url': global_cfg.card_api_base_url,
|
||||
|
||||
@@ -52,6 +52,7 @@ class Device(Base):
|
||||
config_synced_at = Column(DateTime) # set by server when client confirms in-sync
|
||||
info_reviewed_at = Column(DateTime, default=lambda: datetime(1970, 1, 1))
|
||||
card_presence = Column(String(10), default='enable')
|
||||
custom_chrome_url = Column(String(500), nullable=True) # per-device production URL override (overrides WMTGlobalConfig.chrome_url)
|
||||
|
||||
# Relationships
|
||||
logs = relationship("LogEntry", back_populates="device")
|
||||
|
||||
@@ -299,6 +299,8 @@ def device_edit(device_id):
|
||||
device.location = request.form.get('location', '').strip() or None
|
||||
device.card_presence = request.form.get('card_presence', 'enable')
|
||||
device.description = request.form.get('notes', '').strip() or None
|
||||
custom_url = request.form.get('custom_chrome_url', '').strip()
|
||||
device.custom_chrome_url = custom_url if custom_url else None
|
||||
device.config_updated_at = datetime.utcnow()
|
||||
device.info_reviewed_at = datetime.utcnow()
|
||||
flash('Device updated.', 'success')
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"version": "2.9",
|
||||
"notes": "",
|
||||
"uploaded_at": "2026-05-13T13:17:18",
|
||||
"filename": "wmt_v2.9.zip"
|
||||
}
|
||||
Binary file not shown.
+64
-2
@@ -781,11 +781,73 @@
|
||||
}
|
||||
|
||||
body.dark-mode .nav-group-header:hover {
|
||||
background-color: rgba(255,255,255,0.08);
|
||||
background-color: rgba(255,255,255,0.07);
|
||||
}
|
||||
|
||||
body.dark-mode .nav-group-header.open {
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
background-color: rgba(255,255,255,0.09);
|
||||
}
|
||||
|
||||
/* ── Dark mode sidebar ── */
|
||||
body.dark-mode .sidebar {
|
||||
background: linear-gradient(160deg, #0d0d0d 0%, #1a1a2e 50%, #16213e 100%);
|
||||
box-shadow: 2px 0 16px rgba(0,0,0,0.6);
|
||||
}
|
||||
|
||||
body.dark-mode .sidebar .logo {
|
||||
border-bottom-color: rgba(255,255,255,0.08);
|
||||
}
|
||||
|
||||
body.dark-mode .sidebar .logo small {
|
||||
color: #7f8c9a;
|
||||
}
|
||||
|
||||
body.dark-mode .sidebar .nav-link {
|
||||
color: #b0bec5;
|
||||
}
|
||||
|
||||
body.dark-mode .sidebar .nav-link:hover {
|
||||
background-color: rgba(100,181,246,0.12);
|
||||
color: #e0f0ff;
|
||||
}
|
||||
|
||||
body.dark-mode .sidebar .nav-link.active {
|
||||
background-color: rgba(100,181,246,0.2);
|
||||
color: #e0f0ff;
|
||||
border-left: 3px solid #64b5f6;
|
||||
padding-left: 12px;
|
||||
}
|
||||
|
||||
body.dark-mode .sidebar .nav-link i {
|
||||
color: #64b5f6;
|
||||
}
|
||||
|
||||
body.dark-mode .sidebar .nav-link.active i {
|
||||
color: #90caf9;
|
||||
}
|
||||
|
||||
body.dark-mode .sidebar .nav-link.admin-link {
|
||||
color: #ef9a9a;
|
||||
border-top-color: rgba(255,255,255,0.07);
|
||||
}
|
||||
|
||||
body.dark-mode .sidebar .nav-link.admin-link:hover {
|
||||
background-color: rgba(239,154,154,0.15);
|
||||
color: #ffcdd2;
|
||||
}
|
||||
|
||||
body.dark-mode .sidebar .nav-link.admin-link.active {
|
||||
background-color: rgba(239,154,154,0.22);
|
||||
color: #ffcdd2;
|
||||
}
|
||||
|
||||
body.dark-mode .sidebar .nav-link.admin-link i {
|
||||
color: #ef9a9a;
|
||||
}
|
||||
|
||||
body.dark-mode .dark-mode-btn {
|
||||
border-top-color: rgba(255,255,255,0.07);
|
||||
color: #b0bec5;
|
||||
}
|
||||
</style>
|
||||
{% block extra_css %}{% endblock %}
|
||||
|
||||
@@ -72,6 +72,34 @@
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
<h6 class="text-muted mb-1">Chrome Launch – Production URL Override</h6>
|
||||
<p class="text-muted small mb-3">
|
||||
Leave blank to use the global default URL configured in
|
||||
<a href="{{ url_for('wmt_web.settings') }}" target="_blank">WMT Settings</a>.
|
||||
Fill in only if this device needs a different production page.
|
||||
</p>
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-semibold">Custom Production URL
|
||||
<small class="text-muted fw-normal">(device-specific override)</small>
|
||||
</label>
|
||||
<input type="url" name="custom_chrome_url" class="form-control"
|
||||
value="{{ device.custom_chrome_url or '' if device else '' }}"
|
||||
placeholder="Leave blank to use global default">
|
||||
{% if device and device.custom_chrome_url %}
|
||||
<div class="form-text text-warning">
|
||||
<i class="fas fa-exclamation-triangle me-1"></i>
|
||||
This device uses a custom URL instead of the global default.
|
||||
Clear the field to revert to the global setting.
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="form-text text-success">
|
||||
<i class="fas fa-check-circle me-1"></i>
|
||||
Using global default production URL.
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if device %}
|
||||
<div class="alert alert-light border small mb-4">
|
||||
<strong>Last seen:</strong>
|
||||
|
||||
Reference in New Issue
Block a user