From e44f33aa29e8534bdfe7960e678ec7c22f34ac60 Mon Sep 17 00:00:00 2001 From: Darell Tan Date: Sun, 14 May 2023 02:09:17 +0800 Subject: [PATCH] Don't persist Z2M state with "zero" values When storing Z2M state, skip properties with default "zero" values. This should skip devices and properties that were not updated via MQTT yet. --- bridge.go | 23 ++++++++++++++++++----- bridge_test.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/bridge.go b/bridge.go index 59b059f..b57625a 100644 --- a/bridge.go +++ b/bridge.go @@ -11,6 +11,7 @@ import ( "fmt" "log" "net/http" + "reflect" "strings" "sync" "time" @@ -196,6 +197,11 @@ func (br *Bridge) saveZ2MState() error { devState := make(map[string]any) for prop, mapping := range dev.Mappings { + // don't bother persisting property if it is "zero" + if reflect.ValueOf(mapping.Characteristic.Val).IsZero() { + continue + } + v, err := mapping.ToExposedValue(mapping.Characteristic.Val) if err != nil { return err @@ -205,12 +211,19 @@ func (br *Bridge) saveZ2MState() error { } // serialize into JSON - jsonState, err := json.Marshal(devState) - if err != nil { - return err - } + if len(devState) > 0 { + jsonState, err := json.Marshal(devState) + if err != nil { + return err + } - devices[name] = jsonState + devices[name] = jsonState + } + } + + // return early if there was nothing to persist + if len(devices) == 0 { + return nil } allJson, err := json.Marshal(devices) diff --git a/bridge_test.go b/bridge_test.go index 09067fe..294562b 100644 --- a/bridge_test.go +++ b/bridge_test.go @@ -31,6 +31,15 @@ const ContactSensorTemplate = ` } }` +func fileSize(path string) (int64, error) { + fi, err := os.Stat(path) + sz := int64(0) + if err == nil { + sz = fi.Size() + } + return sz, err +} + func TestBridgePersistState(t *testing.T) { dir, err := os.MkdirTemp("", "hapz2m-bridge*") if err != nil { @@ -64,6 +73,27 @@ func TestBridgePersistState(t *testing.T) { t.Errorf("can't persist state: %v", err) } + storeFname := dir + string(os.PathSeparator) + Z2M_STATE_STORE + + if sz, err := fileSize(storeFname); err == nil && sz != 0 { + t.Errorf("expecting defaults to not be persisted, but got size %d, err %v", sz, err) + } + + // alter sensor states to non-defaults + for _, dev := range b.devices { + dev.Mappings["contact"].Characteristic.Val = 1 + } + + // save 2 devices, again + t.Logf("persisting state with non-defaults") + if err := b.saveZ2MState(); err != nil { + t.Errorf("can't persist state: %v", err) + } + + if sz, err := fileSize(storeFname); err != nil || sz == 0 { + t.Errorf("expecting state to be persisted, but got size %d, err %v", sz, err) + } + // re-create with less devices b2 := NewBridge(ctx, dir) b2.AddDevicesFromJSON(fmt.Appendf(nil, "[%s]", s1))