Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f790b21808 | |||
| 0bea6ca4ea | |||
| 2456fd0ee8 | |||
| c133932b29 |
@@ -6,11 +6,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## [1.4.4] - 2026-03-17
|
|
||||||
|
|
||||||
### Removed
|
|
||||||
- `OK_HOURS` and `MISSING_HOURS` config keys and Settings dialog fields removed — unit status thresholds are calculated by terra-view from raw `age_minutes`, not by the watcher. These fields had no effect since v1.4.2.
|
|
||||||
|
|
||||||
## [1.4.3] - 2026-03-17
|
## [1.4.3] - 2026-03-17
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Series 3 Watcher v1.4.4
|
# Series 3 Watcher v1.4.3
|
||||||
|
|
||||||
Monitors Instantel **Series 3 (Minimate)** call-in activity on a Blastware server. Runs as a **system tray app** that starts automatically on login, reports heartbeats to terra-view, and self-updates from Gitea.
|
Monitors Instantel **Series 3 (Minimate)** call-in activity on a Blastware server. Runs as a **system tray app** that starts automatically on login, reports heartbeats to terra-view, and self-updates from Gitea.
|
||||||
|
|
||||||
@@ -71,6 +71,8 @@ All settings live in `config.ini`. The Setup Wizard covers every field, but here
|
|||||||
| Key | Description |
|
| Key | Description |
|
||||||
|-----|-------------|
|
|-----|-------------|
|
||||||
| `SCAN_INTERVAL_SECONDS` | How often to scan the folder (default `300`) |
|
| `SCAN_INTERVAL_SECONDS` | How often to scan the folder (default `300`) |
|
||||||
|
| `OK_HOURS` | Age threshold for OK status (default `12`) |
|
||||||
|
| `MISSING_HOURS` | Age threshold for Missing status (default `24`) |
|
||||||
| `MLG_HEADER_BYTES` | Bytes to read from each `.MLG` header for unit ID (default `2048`) |
|
| `MLG_HEADER_BYTES` | Bytes to read from each `.MLG` header for unit ID (default `2048`) |
|
||||||
| `RECENT_WARN_DAYS` | Log unsniffable files newer than this window |
|
| `RECENT_WARN_DAYS` | Log unsniffable files newer than this window |
|
||||||
|
|
||||||
@@ -121,7 +123,7 @@ To view connected watchers: **Settings → Developer → Watcher Manager**.
|
|||||||
|
|
||||||
## Versioning
|
## Versioning
|
||||||
|
|
||||||
Follows **Semantic Versioning**. Current release: **v1.4.4**.
|
Follows **Semantic Versioning**. Current release: **v1.4.3**.
|
||||||
See `CHANGELOG.md` for full history.
|
See `CHANGELOG.md` for full history.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -23,11 +23,6 @@ if exist "%~dp0icon.ico" (
|
|||||||
pyinstaller --onefile --windowed --name "%EXE_NAME%" series3_tray.py
|
pyinstaller --onefile --windowed --name "%EXE_NAME%" series3_tray.py
|
||||||
)
|
)
|
||||||
|
|
||||||
REM Copy versioned exe to plain name for Inno Setup
|
|
||||||
copy /Y "dist\%EXE_NAME%.exe" "dist\series3-watcher.exe"
|
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
echo Done.
|
echo Done. Check dist\%EXE_NAME%.exe
|
||||||
echo Gitea upload: dist\%EXE_NAME%.exe
|
|
||||||
echo Inno Setup: dist\series3-watcher.exe (copy of above)
|
|
||||||
pause
|
pause
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ MAX_EVENT_AGE_DAYS = 365
|
|||||||
|
|
||||||
# Scanning
|
# Scanning
|
||||||
SCAN_INTERVAL_SECONDS = 30
|
SCAN_INTERVAL_SECONDS = 30
|
||||||
|
OK_HOURS = 12
|
||||||
|
MISSING_HOURS = 24
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
ENABLE_LOGGING = True
|
ENABLE_LOGGING = True
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[Setup]
|
[Setup]
|
||||||
AppName=Series 3 Watcher
|
AppName=Series 3 Watcher
|
||||||
AppVersion=1.4.4
|
AppVersion=1.4.2
|
||||||
AppPublisher=Terra-Mechanics Inc.
|
AppPublisher=Terra-Mechanics Inc.
|
||||||
DefaultDirName={pf}\Series3Watcher
|
DefaultDirName={pf}\Series3Watcher
|
||||||
DefaultGroupName=Series 3 Watcher
|
DefaultGroupName=Series 3 Watcher
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
"""
|
"""
|
||||||
Series 3 Watcher — System Tray Launcher v1.4.4
|
Series 3 Watcher — System Tray Launcher v1.4.3
|
||||||
Requires: pystray, Pillow, tkinter (stdlib)
|
Requires: pystray, Pillow, tkinter (stdlib)
|
||||||
|
|
||||||
Run with: pythonw series3_tray.py (no console window)
|
Run with: pythonw series3_tray.py (no console window)
|
||||||
|
|||||||
@@ -60,6 +60,8 @@ def load_config(path: str) -> Dict[str, Any]:
|
|||||||
return {
|
return {
|
||||||
"WATCH_PATH": get_str("SERIES3_PATH", r"C:\Blastware 10\Event\autocall home"),
|
"WATCH_PATH": get_str("SERIES3_PATH", r"C:\Blastware 10\Event\autocall home"),
|
||||||
"SCAN_INTERVAL": get_int("SCAN_INTERVAL_SECONDS", 300),
|
"SCAN_INTERVAL": get_int("SCAN_INTERVAL_SECONDS", 300),
|
||||||
|
"OK_HOURS": float(get_int("OK_HOURS", 12)),
|
||||||
|
"MISSING_HOURS": float(get_int("MISSING_HOURS", 24)),
|
||||||
"ENABLE_LOGGING": get_bool("ENABLE_LOGGING", True),
|
"ENABLE_LOGGING": get_bool("ENABLE_LOGGING", True),
|
||||||
"LOG_FILE": get_str("LOG_FILE", os.path.join(
|
"LOG_FILE": get_str("LOG_FILE", os.path.join(
|
||||||
os.environ.get("LOCALAPPDATA") or os.environ.get("APPDATA") or "C:\\",
|
os.environ.get("LOCALAPPDATA") or os.environ.get("APPDATA") or "C:\\",
|
||||||
@@ -217,7 +219,7 @@ def scan_latest(
|
|||||||
|
|
||||||
|
|
||||||
# --- API heartbeat / SFM telemetry helpers ---
|
# --- API heartbeat / SFM telemetry helpers ---
|
||||||
VERSION = "1.4.4"
|
VERSION = "1.4.3"
|
||||||
|
|
||||||
|
|
||||||
def _read_log_tail(log_file: str, n: int = 25) -> Optional[list]:
|
def _read_log_tail(log_file: str, n: int = 25) -> Optional[list]:
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
"""
|
"""
|
||||||
Series 3 Watcher — Settings Dialog v1.4.4
|
Series 3 Watcher — Settings Dialog v1.4.3
|
||||||
|
|
||||||
Provides a Tkinter settings dialog that doubles as a first-run wizard.
|
Provides a Tkinter settings dialog that doubles as a first-run wizard.
|
||||||
|
|
||||||
@@ -30,6 +30,8 @@ DEFAULTS = {
|
|||||||
"SERIES3_PATH": r"C:\Blastware 10\Event\autocall home",
|
"SERIES3_PATH": r"C:\Blastware 10\Event\autocall home",
|
||||||
"MAX_EVENT_AGE_DAYS": "365",
|
"MAX_EVENT_AGE_DAYS": "365",
|
||||||
"SCAN_INTERVAL_SECONDS":"300",
|
"SCAN_INTERVAL_SECONDS":"300",
|
||||||
|
"OK_HOURS": "12",
|
||||||
|
"MISSING_HOURS": "24",
|
||||||
"MLG_HEADER_BYTES": "2048",
|
"MLG_HEADER_BYTES": "2048",
|
||||||
"ENABLE_LOGGING": "true",
|
"ENABLE_LOGGING": "true",
|
||||||
"LOG_FILE": os.path.join(
|
"LOG_FILE": os.path.join(
|
||||||
@@ -227,6 +229,8 @@ class SettingsDialog:
|
|||||||
|
|
||||||
# Scanning
|
# Scanning
|
||||||
self.var_scan_interval = tk.StringVar(value=v["SCAN_INTERVAL_SECONDS"])
|
self.var_scan_interval = tk.StringVar(value=v["SCAN_INTERVAL_SECONDS"])
|
||||||
|
self.var_ok_hours = tk.StringVar(value=v["OK_HOURS"])
|
||||||
|
self.var_missing_hours = tk.StringVar(value=v["MISSING_HOURS"])
|
||||||
self.var_mlg_header_bytes = tk.StringVar(value=v["MLG_HEADER_BYTES"])
|
self.var_mlg_header_bytes = tk.StringVar(value=v["MLG_HEADER_BYTES"])
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
@@ -394,7 +398,9 @@ class SettingsDialog:
|
|||||||
def _build_tab_scanning(self, nb):
|
def _build_tab_scanning(self, nb):
|
||||||
f = self._tab_frame(nb, "Scanning")
|
f = self._tab_frame(nb, "Scanning")
|
||||||
_add_label_spinbox(f, 0, "Scan Interval (sec)", self.var_scan_interval, 10, 3600)
|
_add_label_spinbox(f, 0, "Scan Interval (sec)", self.var_scan_interval, 10, 3600)
|
||||||
_add_label_spinbox(f, 1, "MLG Header Bytes", self.var_mlg_header_bytes, 256, 65536)
|
_add_label_spinbox(f, 1, "OK Hours", self.var_ok_hours, 1, 168)
|
||||||
|
_add_label_spinbox(f, 2, "Missing Hours", self.var_missing_hours, 1, 168)
|
||||||
|
_add_label_spinbox(f, 3, "MLG Header Bytes", self.var_mlg_header_bytes, 256, 65536)
|
||||||
|
|
||||||
def _build_tab_logging(self, nb):
|
def _build_tab_logging(self, nb):
|
||||||
f = self._tab_frame(nb, "Logging")
|
f = self._tab_frame(nb, "Logging")
|
||||||
@@ -492,6 +498,8 @@ class SettingsDialog:
|
|||||||
(self.var_api_interval, "API Interval", 30, 3600, 300),
|
(self.var_api_interval, "API Interval", 30, 3600, 300),
|
||||||
(self.var_max_event_age_days, "Max Event Age Days", 1, 3650, 365),
|
(self.var_max_event_age_days, "Max Event Age Days", 1, 3650, 365),
|
||||||
(self.var_scan_interval, "Scan Interval", 10, 3600, 300),
|
(self.var_scan_interval, "Scan Interval", 10, 3600, 300),
|
||||||
|
(self.var_ok_hours, "OK Hours", 1, 168, 12),
|
||||||
|
(self.var_missing_hours, "Missing Hours", 1, 168, 24),
|
||||||
(self.var_mlg_header_bytes, "MLG Header Bytes", 256, 65536, 2048),
|
(self.var_mlg_header_bytes, "MLG Header Bytes", 256, 65536, 2048),
|
||||||
(self.var_log_retention_days, "Log Retention Days", 1, 365, 30),
|
(self.var_log_retention_days, "Log Retention Days", 1, 365, 30),
|
||||||
]
|
]
|
||||||
@@ -524,6 +532,8 @@ class SettingsDialog:
|
|||||||
"SERIES3_PATH": self.var_series3_path.get().strip(),
|
"SERIES3_PATH": self.var_series3_path.get().strip(),
|
||||||
"MAX_EVENT_AGE_DAYS": str(int_values["Max Event Age Days"]),
|
"MAX_EVENT_AGE_DAYS": str(int_values["Max Event Age Days"]),
|
||||||
"SCAN_INTERVAL_SECONDS":str(int_values["Scan Interval"]),
|
"SCAN_INTERVAL_SECONDS":str(int_values["Scan Interval"]),
|
||||||
|
"OK_HOURS": str(int_values["OK Hours"]),
|
||||||
|
"MISSING_HOURS": str(int_values["Missing Hours"]),
|
||||||
"MLG_HEADER_BYTES": str(int_values["MLG Header Bytes"]),
|
"MLG_HEADER_BYTES": str(int_values["MLG Header Bytes"]),
|
||||||
"ENABLE_LOGGING": "true" if self.var_enable_logging.get() else "false",
|
"ENABLE_LOGGING": "true" if self.var_enable_logging.get() else "false",
|
||||||
"LOG_FILE": self.var_log_file.get().strip(),
|
"LOG_FILE": self.var_log_file.get().strip(),
|
||||||
|
|||||||
Reference in New Issue
Block a user