summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxengineering <me@xengineering.eu>2025-12-20 13:00:52 +0100
committerxengineering <me@xengineering.eu>2025-12-20 13:00:52 +0100
commit853e3fd5f2b4e622d4e35c0e3c2fad6c358cb8ae (patch)
tree6939b0a0b92635c5dad80da30079c5b07645bf76
parent8205200e73ff45c09aaa67dacb7ceb9b33845f5d (diff)
downloadsia-server-853e3fd5f2b4e622d4e35c0e3c2fad6c358cb8ae.tar
sia-server-853e3fd5f2b4e622d4e35c0e3c2fad6c358cb8ae.tar.zst
sia-server-853e3fd5f2b4e622d4e35c0e3c2fad6c358cb8ae.zip
Add cache implementation
This avoids frequent MQTT messages containing the same state.
-rw-r--r--cache.go44
-rw-r--r--main.go19
-rw-r--r--meson.build1
3 files changed, 56 insertions, 8 deletions
diff --git a/cache.go b/cache.go
new file mode 100644
index 0000000..081621d
--- /dev/null
+++ b/cache.go
@@ -0,0 +1,44 @@
+package main
+
+import (
+ "fmt"
+ "log"
+
+ mqtt "github.com/eclipse/paho.mqtt.golang"
+)
+
+type States map[string]bool
+
+type Cache struct {
+ Client mqtt.Client
+ States map[string]bool
+}
+
+func NewCache(client mqtt.Client) Cache {
+ var cache Cache
+
+ cache.Client = client
+ cache.States = make(States)
+
+ return cache
+}
+
+func (c *Cache) Update(states States) {
+ if c.States == nil {
+ log.Fatal("Cache states is nil.")
+ }
+
+ if states == nil {
+ log.Fatal("Given states is nil.")
+ }
+
+ for id, state := range states {
+ cached, known := c.States[id]
+ if !known || cached != state {
+ topic := fmt.Sprintf("%s/contact/%s/state", TOPIC_PREFIX, id)
+ payload := []byte(fmt.Sprintf("%t", state))
+ _ = c.Client.Publish(topic, QOS, RETAINED, payload)
+ }
+ c.States[id] = state
+ }
+}
diff --git a/main.go b/main.go
index 6ef4c63..051deef 100644
--- a/main.go
+++ b/main.go
@@ -35,14 +35,18 @@ func main() {
log.Fatalf("Failed startup process: %v", err)
}
+ cache := NewCache(client)
+
for {
start := time.Now()
- err = Poll(req, inventory, client)
+ states, err := Poll(req, inventory)
if err != nil {
log.Fatalf("Failed to poll states: %v", err)
}
+ cache.Update(states)
+
WaitUntil(start.Add(POLLING_PERIOD))
}
}()
@@ -102,21 +106,20 @@ func Stop(c mqtt.Client) {
log.Println("Disconnected from MQTT broker.")
}
-func Poll(req homematic.Requester, inventory homematic.Devices, client mqtt.Client) error {
+func Poll(req homematic.Requester, inventory homematic.Devices) (States, error) {
+ states := make(States)
+
for _, device := range inventory {
if device.Type == `SHUTTER_CONTACT` {
state, err := req.GetValue(device.Address)
if err != nil {
- return fmt.Errorf("Failed to get value: %w", err)
+ return states, fmt.Errorf("Failed to get value: %w", err)
}
-
- topic := fmt.Sprintf("%s/contact/%s/state", TOPIC_PREFIX, device.Address)
- payload := []byte(fmt.Sprintf("%t", state))
- _ = client.Publish(topic, QOS, RETAINED, payload)
+ states[device.Address] = state
}
}
- return nil
+ return states, nil
}
func Await(signals ...syscall.Signal) {
diff --git a/meson.build b/meson.build
index d264c35..e2ce711 100644
--- a/meson.build
+++ b/meson.build
@@ -5,6 +5,7 @@ go = find_program('go', required : true)
sia_server = custom_target(
input : [
meson.current_source_dir() / 'main.go',
+ meson.current_source_dir() / 'cache.go',
],
output : 'sia-server',
command : [