Skip to content

Commit 1da51e8

Browse files
committed
v0.5.5: protocol detection, SAT fallback, device_overrides, --discover
- Use --scan-open on first poll for accurate protocol detection (falls back to --scan if unsupported) - Auto-retry SCSI drives with -d sat on open failure; cache working protocol for subsequent polls - Add device_overrides config for Synology /dev/sata* and RAID paths - Add --discover diagnostic flag with platform detection and optional config write Fixes #16 (QNAP SAT), #17 (Synology device paths)
1 parent bc55a09 commit 1da51e8

4 files changed

Lines changed: 553 additions & 23 deletions

File tree

CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,23 @@
22

33
All notable changes to SMART Sniffer are documented here.
44

5+
## v0.5.5 -- 2026-04-24
6+
7+
Agent-only release. No integration or installer changes required.
8+
9+
Addresses issues [#16](https://github.com/DAB-LABS/smart-sniffer/issues/16) (QNAP SATA drives misreported as SCSI) and [#17](https://github.com/DAB-LABS/smart-sniffer/issues/17) (Synology `/dev/sata*` paths not discovered by scan).
10+
11+
### Added
12+
- **NAS protocol auto-detection on startup** -- the agent now uses `smartctl --scan-open` on its first scan cycle instead of `--scan`. This opens device handles and gives more accurate protocol detection, which fixes QNAP HBAs that report SATA drives as SCSI. Subsequent cycles revert to regular `--scan` to avoid waking sleeping drives.
13+
- **SAT fallback for misreported SCSI drives** -- if a drive is reported as SCSI but smartctl cannot read it, the agent automatically retries with `-d sat` (SCSI-to-ATA Translation). If that works, the agent uses SAT for that drive going forward and logs it once. No config required -- QNAP users affected by #16 should see this pick up their drives automatically.
14+
- **`device_overrides` config option** -- for drives that need an explicit protocol the agent cannot auto-detect (Synology `/dev/sata*` paths, RAID controllers with custom `-d` syntax), you can now list them in `config.yaml`. Overridden devices are treated as first-class drives even if they are not found by `--scan`.
15+
- **`--discover` diagnostic flag** -- run `smartha-agent --discover` to probe every drive, test protocol detection, check SAT fallback, and print a clear summary of what the agent will see at runtime. On Synology, it also probes `/dev/sata1` through `/dev/sata8`. If any drives need `device_overrides`, it offers to write the config for you. Useful for support: paste the output into a GitHub issue and we can diagnose protocol problems without asking for manual smartctl runs.
16+
17+
### Upgrade Notes
18+
- **Agent update only.** Replace the binary or re-run the installer. No integration update, config migration, or installer re-run is required.
19+
- **QNAP users affected by #16:** update the agent -- no config change needed. The SAT fallback handles this automatically.
20+
- **Synology users affected by #17:** update the agent and run `smartha-agent --discover` to generate the `device_overrides` block for your config. Restart the agent after writing the config.
21+
522
## v0.5.4 -- 2026-04-21
623

724
Integration-only release. No agent changes required.

agent/config.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@ type FilesystemConfig struct {
2020
Device string `yaml:"device"`
2121
}
2222

23+
// DeviceOverride allows manual protocol specification for drives that
24+
// auto-detection cannot handle (Synology paths, RAID controllers, etc.).
25+
type DeviceOverride struct {
26+
Device string `yaml:"device"`
27+
Protocol string `yaml:"protocol"`
28+
}
29+
2330
// Config holds all agent configuration. Values are resolved with this
2431
// precedence: CLI flags > config file > defaults.
2532
type Config struct {
@@ -31,6 +38,9 @@ type Config struct {
3138
MDNSName string `yaml:"mdns_name"` // custom mDNS instance name (default: smartha-<hostname>)
3239
Filesystems []FilesystemConfig `yaml:"filesystems"` // empty = disk usage monitoring disabled
3340
StandbyMode string `yaml:"standby_mode"` // never, standby, sleep, idle (default: never)
41+
DeviceOverrides []DeviceOverride `yaml:"device_overrides"` // manual protocol overrides per device path
42+
Discover bool `yaml:"-"` // set by --discover flag; not read from config file
43+
NoWrite bool `yaml:"-"` // set by --no-write flag; skips config write in discover mode
3444
}
3545

3646
// defaultConfig returns sane defaults.
@@ -70,6 +80,8 @@ func LoadConfig() (*Config, error) {
7080
noMDNS := flag.Bool("no-mdns", false, "Disable mDNS/Zeroconf service advertisement")
7181
advIface := flag.String("interface", "", "Restrict mDNS advertisement to this network interface")
7282
mdnsName := flag.String("mdns-name", "", "Custom mDNS instance name (default: smartha-<hostname>)")
83+
discover := flag.Bool("discover", false, "Probe drives and detect protocols (diagnostic tool)")
84+
noWrite := flag.Bool("no-write", false, "With --discover: print proposed overrides but do not write config")
7385
flag.Parse()
7486

7587
// --- Attempt to load config.yaml ---
@@ -116,6 +128,12 @@ func LoadConfig() (*Config, error) {
116128
if *mdnsName != "" {
117129
cfg.MDNSName = *mdnsName
118130
}
131+
if *discover {
132+
cfg.Discover = true
133+
}
134+
if *noWrite {
135+
cfg.NoWrite = true
136+
}
119137

120138
// Sanity checks
121139
if cfg.Port < 1 || cfg.Port > 65535 {
@@ -136,6 +154,16 @@ func LoadConfig() (*Config, error) {
136154
return nil, fmt.Errorf("invalid standby_mode %q (must be never, standby, sleep, or idle)", cfg.StandbyMode)
137155
}
138156

157+
// Validate device_overrides
158+
for i, ov := range cfg.DeviceOverrides {
159+
if ov.Device == "" {
160+
return nil, fmt.Errorf("device_overrides[%d]: device path is required", i)
161+
}
162+
if ov.Protocol == "" {
163+
return nil, fmt.Errorf("device_overrides[%d]: protocol is required for %s", i, ov.Device)
164+
}
165+
}
166+
139167
return &cfg, nil
140168
}
141169

0 commit comments

Comments
 (0)