From 1ee9a3bd72440de21a170bc67eb8515044fab1a6 Mon Sep 17 00:00:00 2001
From: jkerdreux-imt <jerome.kerdreux@imt-atlantique.fr>
Date: Wed, 5 Feb 2025 17:58:29 +0100
Subject: [PATCH] PowerRelay work in progress

I get powerrelay to work partially (able to get the right state).. but
this *** ZwaveJS API use 2 values (one for get/one for set..). So still
unable to switch the relays ;(
---
 .../protocols/ZwaveJS/xaal/zwavejs/devices.py | 91 ++++++++++++++-----
 devices/protocols/ZwaveJS/xaal/zwavejs/gw.py  |  6 +-
 2 files changed, 72 insertions(+), 25 deletions(-)

diff --git a/devices/protocols/ZwaveJS/xaal/zwavejs/devices.py b/devices/protocols/ZwaveJS/xaal/zwavejs/devices.py
index f4058894..5944baff 100644
--- a/devices/protocols/ZwaveJS/xaal/zwavejs/devices.py
+++ b/devices/protocols/ZwaveJS/xaal/zwavejs/devices.py
@@ -1,18 +1,21 @@
-from xaal.schemas import devices
+import pdb
+from logging import getLogger
 
+from zwave_js_server.event import Event
 from zwave_js_server.model.node import Node
 from zwave_js_server.model.value import Value
-from zwave_js_server.event import Event
-
-from logging import getLogger
 
-from .cmdclass import COMMAND_CLASS
+from xaal.schemas import devices
+from xaal.lib import tools, bindings, AsyncEngine, Device
 
-import pdb
 
+from .cmdclass import COMMAND_CLASS
+from . import const
 
 logger = getLogger(__name__)
 
+BASE_ADDR = tools.get_uuid('74fd7cf2-a349-46af-bbaf-41d98fab0000')
+
 
 def get_property_id(value: Value):
     if value.property_ in ["value", "currentValue", "targetValue"]:
@@ -20,22 +23,44 @@ def get_property_id(value: Value):
     return "--" + str(value.property_name)
 
 
-def dump_value(value: Value):
+def value_dump(value: Value):
     print(f"[{value}] {'0x%x'%value.command_class} {value.endpoint} {get_property_id(value)} => {value.value}")
 
 
-def build_devices(node: Node):
+def value_is_command_class(value: Value, command_class: COMMAND_CLASS):
+    return value.command_class == command_class.value
+
+
+def value_is_value(value: Value):
+    return value.property_ in ["value", "currentValue"]
+
+
+def build_devices(node: Node, eng: AsyncEngine):
     config = node.device_config
     logger.info(f"{node.node_id} {config.manufacturer}/{config.label} ")
     # node.on("value updated", self.value_updated)
     # pdb.set_trace()
+    #
+
+    base_addr = BASE_ADDR + node.node_id * 128
     for k in node.values:
         value = node.values.get(k)
-        assert value
-        if value.command_class == COMMAND_CLASS.SWITCH_BINARY.value and value.property_ == 'currentValue':
-            dump_value(value)
-        if value.command_class == COMMAND_CLASS.METER.value and value.property_ == 'value':
-            dump_value(value)
+        if value is None or not value_is_value(value):
+            continue
+        base_addr = base_addr + 1
+        value_dump(value)
+
+        obj = None
+        if value_is_command_class(value, COMMAND_CLASS.SWITCH_BINARY):
+            obj = PowerRelay(node, value, base_addr)
+
+        if value_is_command_class(value, COMMAND_CLASS.METER):
+            # obj = PowerMeter(node, value, base_addr)
+            pass
+
+        if obj is not None and obj.dev:
+            obj.setup()
+            eng.add_device(obj.dev)
 
     # if node.node_id == 5:
     # pdb.set_trace()
@@ -44,25 +69,47 @@ def build_devices(node: Node):
 class ZwaveDevice(object):
     def __init__(self, node: Node):
         self.node = node
+        self.dev: Device | None = None
 
     def setup(self):
-        pass
+        assert self.dev
+        dev = self.dev
+        dev.vendor_id = f"ZwaveJS/{self.node.device_config.manufacturer}"
+        dev.product_id = f"{self.node.device_config.label}"
+        dev.info = f"{self.node.node_id}"
+        self.node.on(const.EVT_VALUE_UPDATED, self.update)
 
     def update(self, event: Event):
-        pass
+        print(event)
 
 
 class PowerRelay(ZwaveDevice):
-    def __init__(self, node):
+    def __init__(self, node: Node, value: Value, base_addr: bindings.UUID):
         super().__init__(node)
-        self.dev = devices.powerrelay()
+        dev = devices.powerrelay(base_addr)
+        dev.methods["turn_on"] = self.turn_on
+        dev.methods["turn_off"] = self.turn_off
+        dev.attributes["power"] = value.value
+        self.dev = dev
+        self.state = value
+
+    def update(self, event: Event):
+        if self.dev:
+            value = event['value']
+            if self.state == value:
+                self.dev.attributes["power"] = value.value
+
+    async def turn_on(self):
+        pdb.set_trace()
+        await self.node.async_set_value(self.state, True)
+
+    async def turn_off(self):
+        await self.node.async_set_value(self.state, False)
 
 
 class PowerMeter(ZwaveDevice):
-    def __init__(self, node):
+    def __init__(self, node: Node, value: Value, base_addr: bindings.UUID):
         super().__init__(node)
-        self.dev = devices.powermeter()
+        self.state = value
+        self.dev = devices.powermeter(base_addr)
         self.dev.unsupported_attributes = ['devices']
-
-    def update(self, event: Event):
-        print(event)
diff --git a/devices/protocols/ZwaveJS/xaal/zwavejs/gw.py b/devices/protocols/ZwaveJS/xaal/zwavejs/gw.py
index cb3d1c9c..d5cfdee1 100644
--- a/devices/protocols/ZwaveJS/xaal/zwavejs/gw.py
+++ b/devices/protocols/ZwaveJS/xaal/zwavejs/gw.py
@@ -58,9 +58,9 @@ class GW:
         nodes = self.client.driver.controller.nodes
         for node in nodes.values():
             if node.ready:
-                build_devices(node)
-                if DEBUG:
-                    node.on(EVT_VALUE_UPDATED, self.dump_event)
+                build_devices(node, self.engine)
+                # if DEBUG:
+                # node.on(EVT_VALUE_UPDATED, self.dump_event)
 
     def dump_event(self, event):
         cmd_class = int(event["args"]["commandClass"])
-- 
GitLab