homebridge-smartsystem 6.8.18 → 7.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/.vscode/launch.json +15 -4
  2. package/MIXINS-GUIDE.md +210 -0
  3. package/README.md +31 -0
  4. package/SETTINGS-UPDATE.md +195 -0
  5. package/TESTING-GUIDE.md +220 -0
  6. package/WEBSOCKET-API.md +303 -0
  7. package/config.json +57 -19
  8. package/duotecno/types.js +48 -2
  9. package/duotecno/types.ts +79 -1
  10. package/package.json +7 -3
  11. package/raspberry-pi-setup.sh +80 -0
  12. package/server/HA-API.js +4 -1
  13. package/server/HA-API.ts +4 -1
  14. package/server/HB.js +6 -1
  15. package/server/HB.ts +5 -1
  16. package/server/mDNS.js +168 -0
  17. package/server/mDNS.ts +198 -0
  18. package/server/platform.js +7 -0
  19. package/server/platform.ts +8 -0
  20. package/server/proxy.js +58 -19
  21. package/server/proxy.ts +31 -3
  22. package/server/smartapp.js +412 -18
  23. package/server/smartapp.ts +450 -20
  24. package/server/socapp.js +2 -1
  25. package/server/socapp.ts +2 -1
  26. package/server/views/assets/Duotecno_logo_black.svg +10 -0
  27. package/server/views/assets/Duotecno_logo_white.svg +10 -0
  28. package/server/views/device-details.ejs +139 -0
  29. package/server/views/device-list.ejs +44 -0
  30. package/server/views/footer.ejs +0 -1
  31. package/server/views/head.ejs +9 -0
  32. package/server/views/homekit.ejs +2 -9
  33. package/server/views/link-details.ejs +2 -15
  34. package/server/views/link-list.ejs +2 -9
  35. package/server/views/login.ejs +8 -9
  36. package/server/views/master-detail.ejs +3 -9
  37. package/server/views/master-list.ejs +3 -10
  38. package/server/views/nav.ejs +44 -11
  39. package/server/views/node-details.ejs +1 -8
  40. package/server/views/power-binding.ejs +3 -10
  41. package/server/views/power-rule.ejs +3 -10
  42. package/server/views/power.ejs +8 -15
  43. package/server/views/proxy.ejs +1 -8
  44. package/server/views/scripts.ejs +10 -0
  45. package/server/views/service-list.ejs +2 -9
  46. package/server/views/settings.ejs +61 -22
  47. package/server/views/style.ejs +49 -5
  48. package/server/views/switch-details.ejs +2 -9
  49. package/server/views/switch-list.ejs +2 -9
  50. package/server/webapp.js +150 -11
  51. package/server/webapp.ts +166 -14
  52. package/{index.spec.js → testHB.js} +1 -1
  53. package/{run.js → testProxy.js} +2 -2
  54. package/{run.ts → testProxy.ts} +1 -1
  55. package/testWS.js +137 -0
  56. package/testWS.ts +174 -0
  57. package/run9998.js +0 -7
  58. package/run9998.ts +0 -6
  59. package/run9999.js +0 -7
  60. package/run9999.ts +0 -6
  61. /package/{index.spec.ts → testHB.ts} +0 -0
@@ -6,8 +6,8 @@
6
6
  "request": "launch",
7
7
  "smartStep": true,
8
8
  "sourceMaps": true,
9
- "name": "Test Platform",
10
- "program": "${workspaceFolder}/index.spec.js",
9
+ "name": "Test HB Platform",
10
+ "program": "${workspaceFolder}/testHB.js",
11
11
  "skipFiles": [
12
12
  "<node_internals>/**"
13
13
  ]
@@ -17,8 +17,19 @@
17
17
  "request": "launch",
18
18
  "smartStep": true,
19
19
  "sourceMaps": true,
20
- "name": "Run SmartSocket",
21
- "program": "${workspaceFolder}/run.js",
20
+ "name": "Run SmartSocket Proxy",
21
+ "program": "${workspaceFolder}/testProxy.js",
22
+ "skipFiles": [
23
+ "<node_internals>/**"
24
+ ]
25
+ },
26
+ {
27
+ "type": "node",
28
+ "request": "launch",
29
+ "smartStep": true,
30
+ "sourceMaps": true,
31
+ "name": "Run Test Websockets",
32
+ "program": "${workspaceFolder}/testWS.js",
22
33
  "skipFiles": [
23
34
  "<node_internals>/**"
24
35
  ]
@@ -0,0 +1,210 @@
1
+ # TypeScript Mixins Pattern for SmartApp
2
+
3
+ ## Overview
4
+
5
+ Your SmartApp is getting large because it handles multiple concerns:
6
+ - Device management (WebSocket, power measurements)
7
+ - Link management (Homebridge accessories)
8
+ - Switch management (HTTP switches)
9
+ - Power management (Smappee, P1, Shelly)
10
+ - Proxy configuration
11
+ - Settings management
12
+
13
+ TypeScript doesn't support multiple inheritance, but **mixins** provide a similar capability.
14
+
15
+ ## Solution Options
16
+
17
+ ### **Option 1: Mixin Pattern** (Most Flexible)
18
+
19
+ Create separate mixin functions that add functionality to your class:
20
+
21
+ ```typescript
22
+ // server/mixins/DeviceMixin.ts
23
+ type Constructor<T = {}> = new (...args: any[]) => T;
24
+
25
+ export interface DeviceMixinBase {
26
+ devices: Array<Device>;
27
+ system: System;
28
+ power: Power;
29
+ // ... other required properties
30
+ }
31
+
32
+ export function DeviceMixin<TBase extends Constructor<DeviceMixinBase>>(Base: TBase) {
33
+ return class extends Base {
34
+ setupWebSocketServers() { /* ... */ }
35
+ sendDeviceList(ws: WebSocket) { /* ... */ }
36
+ getDeviceList() { /* ... */ }
37
+ // ... all device-related methods
38
+ };
39
+ }
40
+
41
+ // Usage in smartapp.ts
42
+ import { DeviceMixin } from './mixins/DeviceMixin';
43
+ import { LinkMixin } from './mixins/LinkMixin';
44
+ import { SwitchMixin } from './mixins/SwitchMixin';
45
+
46
+ // Apply mixins
47
+ const SmartAppBase = SwitchMixin(LinkMixin(DeviceMixin(WebApp)));
48
+
49
+ export class SmartApp extends SmartAppBase {
50
+ // Only SmartApp-specific logic here
51
+ constructor(system: System, power: Power, platform: Platform) {
52
+ super("smartapp");
53
+ // ...
54
+ }
55
+ }
56
+ ```
57
+
58
+ **Pros:**
59
+ - True composition - each mixin is independent
60
+ - Can be reused across different classes
61
+ - TypeScript type-safe
62
+ - Easy to test mixins individually
63
+
64
+ **Cons:**
65
+ - Requires some boilerplate
66
+ - Mixing order matters
67
+ - Can be confusing at first
68
+
69
+ ---
70
+
71
+ ### **Option 2: Delegate Pattern** (Simpler)
72
+
73
+ Create separate service/manager classes and delegate to them:
74
+
75
+ ```typescript
76
+ // server/services/DeviceManager.ts
77
+ export class DeviceManager {
78
+ constructor(
79
+ private devices: Array<Device>,
80
+ private system: System,
81
+ private power: Power
82
+ ) {}
83
+
84
+ setupWebSocketServers(servers: http.Server[]) { /* ... */ }
85
+ getDeviceList() { /* ... */ }
86
+ // ... all device methods
87
+ }
88
+
89
+ // server/services/LinkManager.ts
90
+ export class LinkManager {
91
+ constructor(
92
+ private links: Array<Link>,
93
+ private system: System
94
+ ) {}
95
+
96
+ initLinks() { /* ... */ }
97
+ updateLink(inx: number, link: Link) { /* ... */ }
98
+ // ... all link methods
99
+ }
100
+
101
+ // In smartapp.ts
102
+ export class SmartApp extends WebApp {
103
+ private deviceManager: DeviceManager;
104
+ private linkManager: LinkManager;
105
+
106
+ constructor(system: System, power: Power, platform: Platform) {
107
+ super("smartapp");
108
+
109
+ this.deviceManager = new DeviceManager(this.devices, this.system, this.power);
110
+ this.linkManager = new LinkManager(this.links, this.system);
111
+ }
112
+
113
+ // Delegate to managers
114
+ setupWebSocketServers() {
115
+ this.deviceManager.setupWebSocketServers(this.servers);
116
+ }
117
+
118
+ initLinks() {
119
+ this.linkManager.initLinks();
120
+ }
121
+ }
122
+ ```
123
+
124
+ **Pros:**
125
+ - Simple and intuitive
126
+ - Easy to understand
127
+ - Good separation of concerns
128
+ - Easy to unit test
129
+
130
+ **Cons:**
131
+ - More delegation boilerplate
132
+ - Not as "clean" as mixins
133
+ - Managers need access to SmartApp state
134
+
135
+ ---
136
+
137
+ ### **Option 3: Module Pattern** (Most Practical)
138
+
139
+ Split into separate modules but keep in same class:
140
+
141
+ ```typescript
142
+ // server/smartapp/devices.ts
143
+ export class DeviceManagement {
144
+ static setupWebSocketServers(app: SmartApp) { /* ... */ }
145
+ static getDeviceList(app: SmartApp) { /* ... */ }
146
+ // ... all device methods as static functions
147
+ }
148
+
149
+ // server/smartapp/links.ts
150
+ export class LinkManagement {
151
+ static initLinks(app: SmartApp) { /* ... */ }
152
+ static updateLink(app: SmartApp, inx: number, link: Link) { /* ... */ }
153
+ }
154
+
155
+ // In smartapp.ts
156
+ import { DeviceManagement } from './smartapp/devices';
157
+ import { LinkManagement } from './smartapp/links';
158
+
159
+ export class SmartApp extends WebApp {
160
+ setupWebSocketServers() {
161
+ DeviceManagement.setupWebSocketServers(this);
162
+ }
163
+
164
+ initLinks() {
165
+ LinkManagement.initLinks(this);
166
+ }
167
+ }
168
+ ```
169
+
170
+ **Pros:**
171
+ - Simple to implement
172
+ - Code is organized in separate files
173
+ - No complex patterns needed
174
+ - Easy to refactor incrementally
175
+
176
+ **Cons:**
177
+ - Still some methods in main class
178
+ - Not true composition
179
+ - Methods take `app` parameter
180
+
181
+ ---
182
+
183
+ ## **Recommended Approach**
184
+
185
+ For your situation, I'd recommend **Option 2 (Delegate Pattern)** or **Option 3 (Module Pattern)**.
186
+
187
+ Here's why:
188
+ 1. **Easier to understand** - no complex mixin magic
189
+ 2. **Incremental refactoring** - move one feature at a time
190
+ 3. **Better testability** - each manager/module is isolated
191
+ 4. **Clearer dependencies** - you see what each part needs
192
+
193
+ ### Quick Win: Module Pattern
194
+
195
+ Split your 1680-line smartapp.ts into:
196
+
197
+ ```
198
+ server/
199
+ smartapp.ts (main class, ~300 lines)
200
+ smartapp/
201
+ devices.ts (WebSocket & power, ~300 lines)
202
+ links.ts (Homebridge links, ~200 lines)
203
+ switches.ts (HTTP switches, ~200 lines)
204
+ power.ts (Power bindings, ~150 lines)
205
+ proxy.ts (Proxy config, ~150 lines)
206
+ routes.ts (HTTP routing, ~200 lines)
207
+ units.ts (Unit management, ~150 lines)
208
+ ```
209
+
210
+ Would you like me to help you refactor SmartApp using one of these patterns?
package/README.md CHANGED
@@ -317,6 +317,9 @@ Homebridge UI version
317
317
  - 11: use new DNS entries + exponential backoff for new connections, give up after 16 seconds.
318
318
  - 12, 13: small changes for missing value for Target...
319
319
 
320
+ ### v7.0.0 - 12/11/2025
321
+ - 0: added mDNS/Bonjour + always port 80 + don't preload EJS files if system.debug == true
322
+
320
323
  ## Hardware
321
324
  A Raspberry Pi that connects to a Duotecno IP Node
322
325
  and (if configured) to a Smappee Infinity (power and plugs)
@@ -348,6 +351,34 @@ and linked to HB accessories (from v6.7)
348
351
  * scenes (a collection of units + a state) that are triggers by a status change (moods, inputs, ...)
349
352
  * backup / restore
350
353
 
354
+ * Jullix:
355
+
356
+ * I would now like to have a websocket server (on the same ports as the SmartApp) that uses JSON as format.
357
+ * The client that connects can send 2 things: see below, but we should always answer with a number of "switchable items" (relays) together with the power/energy usaged, either measured of estimated (measured: false).
358
+ * An example we could send:
359
+ ```
360
+ [
361
+ { "id": 1, "name": "Airco", "power": 1.0, "energy": 10.0, "voltage": 230.0, "current": 1.0, "relay": true, "measured": true},
362
+ { "id": 2, "name": "Zwembad pomp", "power": 1.0, "energy": 10.0, "voltage": 230.0, "current": 1.0, "relay": true, "measured": false}
363
+ ]
364
+ ```
365
+
366
+ * What we send / what is in this array needs to be configured though a new section in the web interface.
367
+
368
+
369
+ The id's of the relays should be node-numbers * 256 + unit-numbers of Duotecno units (of the first master) and the web/config-page should allow the user to add a "Device" and fill in the details (no id given) + edit a device already in the list. (pass id) (similar as in link-list.ejs and link-details.ejs)
370
+
371
+ * Messages we could receive:
372
+ [] (empty array) keep of keep alice / poll for status
373
+ ```
374
+ [
375
+ { "id": 513 "relay": true },
376
+ { "id": 258, "relay": false }
377
+ ]
378
+ ```
379
+ which would mean: turn unit 1 in node 2 (from 513=2*256+1) "on" and turn unit 2 of node 1 "off" (from 258=1*256+2)
380
+
381
+
351
382
 
352
383
  ## How to set up
353
384
  1. Configure IP address of the Raspberry on the SDCard on a PC or Mac (put it in, edit cmdline.txt and you’re done), perhaps DHCP? WiFi?
@@ -0,0 +1,195 @@
1
+ # Settings Page Update
2
+
3
+ ## Changes Made
4
+
5
+ ### 1. Cleaned Up Settings Page
6
+ - **Removed** conflicting buttons from header (Reset to DHCP, Install IP Settings, Reboot PI)
7
+ - **Added** proper "Save Settings" button with icon
8
+ - **Added** "Restart Server" button (functional) with icon
9
+ - **Commented out** temporarily disabled network configuration fields
10
+ - **Commented out** temporarily disabled system action buttons
11
+
12
+ ### 2. Added Save Functionality
13
+ - New "Save Settings" button that saves the mDNS configuration
14
+ - Success message displayed after saving
15
+ - Reminder to restart server for changes to take effect
16
+
17
+ ### 3. Temporarily Disabled Features
18
+ The following features are commented out with TODO notes pending proper implementation:
19
+
20
+ **Network Configuration (commented in EJS):**
21
+ - Primary Fixed IP Address / netmask
22
+ - Gateway
23
+ - Nameservers
24
+ - Secondary IP configuration
25
+
26
+ **System Actions (commented in EJS):**
27
+ - Reboot System button
28
+ - Reset to DHCP button
29
+ - Install IP Settings button
30
+
31
+ **Backend Handlers (commented in smartapp.ts):**
32
+ - `install` action - writeDHCP functionality
33
+ - `reset` action - resetDHCP and reboot
34
+ - `reboot` action - system reboot
35
+
36
+ ### 4. Active Features
37
+ Currently working features in Settings:
38
+
39
+ ✅ **mDNS Service Name Configuration**
40
+ - Input field for mDNS name
41
+ - Default value: "duotecno-gateway"
42
+ - Help text showing resulting .local address
43
+ - Save button stores configuration
44
+
45
+ ✅ **Save Settings**
46
+ - Saves mDNS configuration to settings file
47
+ - Shows success message
48
+ - Logs configuration change
49
+
50
+ ✅ **Restart Server**
51
+ - Functional restart button (orange color)
52
+ - Restarts the Node.js process
53
+ - Allows mDNS changes to take effect
54
+
55
+ ### 5. UI Improvements
56
+
57
+ **Message Display:**
58
+ - Green success message when settings saved
59
+ - Orange info message for disabled features
60
+ - Icon indicators (checkmark for success, info icon for warnings)
61
+
62
+ **Button Styling:**
63
+ - Save button: Blue with save icon
64
+ - Restart button: Orange with refresh icon
65
+ - Disabled buttons: Commented out (red for reboot, grey for reset, blue for install)
66
+
67
+ **Layout:**
68
+ - Clear section header: "mDNS Configuration"
69
+ - TODO comment explaining why network settings are disabled
70
+ - Clean, focused interface for current functionality
71
+
72
+ ## Usage
73
+
74
+ ### To Configure mDNS Name:
75
+
76
+ 1. Navigate to `/settings`
77
+ 2. Enter desired mDNS name (e.g., "garage-gateway")
78
+ 3. Click "Save Settings"
79
+ 4. See success message
80
+ 5. Click "Restart Server" to apply changes
81
+ 6. Access gateway at: `http://{your-name}.local/`
82
+
83
+ ### Current Button Actions:
84
+
85
+ | Button | Action | Status |
86
+ |--------|--------|--------|
87
+ | Save Settings | Saves mDNS config | ✅ Working |
88
+ | Restart Server | Restarts Node.js process | ✅ Working |
89
+ | Reboot System | System reboot | ⏸️ Disabled (commented) |
90
+ | Reset to DHCP | Reset network config | ⏸️ Disabled (commented) |
91
+ | Install IP Settings | Write DHCP config | ⏸️ Disabled (commented) |
92
+
93
+ ## Technical Details
94
+
95
+ ### Settings File Structure
96
+ ```json
97
+ {
98
+ "network": {
99
+ "ip1": "",
100
+ "gateway1": "",
101
+ "nameservers": "",
102
+ "ip2": "",
103
+ "gateway2": ""
104
+ },
105
+ "mdnsName": "duotecno-gateway"
106
+ }
107
+ ```
108
+
109
+ ### Handler Logic (smartapp.ts)
110
+
111
+ **Save Action:**
112
+ ```typescript
113
+ if (context.action === "save") {
114
+ config = this.scrapeSettings(context);
115
+ this.write("settings", config);
116
+ message = "Settings saved successfully. Restart the server for changes to take effect.";
117
+ log("smartapp", "Settings saved. mDNS name updated to: " + config.mdnsName);
118
+ }
119
+ ```
120
+
121
+ **Restart Action:**
122
+ ```typescript
123
+ else if (context.action === "restart") {
124
+ context.request = "restart";
125
+ return this.doRestart(false)
126
+ }
127
+ ```
128
+
129
+ **Disabled Actions:**
130
+ ```typescript
131
+ else if (context.action === "install") {
132
+ message = "Network IP configuration is temporarily disabled. Use 'Save Settings' for mDNS configuration.";
133
+ // TODO: Re-implement DHCP configuration
134
+ }
135
+ ```
136
+
137
+ ## Future Work
138
+
139
+ ### TODO List:
140
+ 1. ✅ Test Devices WebSocket functionality (priority)
141
+ 2. ⏳ Re-implement DHCP configuration properly
142
+ 3. ⏳ Re-enable network IP settings fields
143
+ 4. ⏳ Re-enable system reboot functionality
144
+ 5. ⏳ Add validation for mDNS name format
145
+ 6. ⏳ Test network configuration on actual Raspberry Pi
146
+ 7. ⏳ Add confirmation dialog for reboot action
147
+
148
+ ### Implementation Notes:
149
+
150
+ **DHCP Configuration Issues:**
151
+ - Writing to `/etc/dhcpcd.conf` may require root privileges
152
+ - Need to test on actual Raspberry Pi hardware
153
+ - Consider using `nmcli` or `netplan` for modern systems
154
+ - Add error handling for file write failures
155
+
156
+ **Reboot Functionality:**
157
+ - Requires appropriate system permissions
158
+ - May need `sudo` or specific user group membership
159
+ - Consider adding confirmation dialog
160
+ - Add timeout before reboot to allow user to see message
161
+
162
+ ## Testing
163
+
164
+ ### Test Save Settings:
165
+ 1. Navigate to `/settings`
166
+ 2. Change mDNS name to "test-gateway"
167
+ 3. Click "Save Settings"
168
+ 4. Verify success message appears
169
+ 5. Check console log for: "Settings saved. mDNS name updated to: test-gateway"
170
+ 6. Verify settings file updated: `cat server/config.json | grep mdnsName`
171
+
172
+ ### Test Restart Server:
173
+ 1. Click "Restart Server" button
174
+ 2. Server should restart gracefully
175
+ 3. mDNS service should re-register with new name
176
+ 4. Verify accessible at: `http://test-gateway.local/`
177
+
178
+ ### Verify Disabled Features:
179
+ 1. Network IP fields should be commented out (not visible)
180
+ 2. System action buttons should be commented out (not visible)
181
+ 3. No errors in console when loading `/settings`
182
+ 4. Form should only show mDNS configuration and two buttons
183
+
184
+ ## Summary
185
+
186
+ The Settings page is now **focused and functional** with:
187
+ - ✅ mDNS name configuration working
188
+ - ✅ Save button added
189
+ - ✅ Restart server button working
190
+ - ✅ Success/info messages displayed
191
+ - ✅ Clean UI with proper icons
192
+ - 🔒 Network configuration temporarily disabled pending fixes
193
+ - 📝 Clear TODO notes for future implementation
194
+
195
+ Priority remains on testing the Devices WebSocket functionality before re-enabling network configuration features.
@@ -0,0 +1,220 @@
1
+ # Testing WebSocket Device Control
2
+
3
+ ## Setup Complete ✅
4
+
5
+ I've added 2 test devices to your `config.json`:
6
+
7
+ 1. **Test Lamp** (Node 3, Unit 34, ID: 802)
8
+ - Estimated power: 100W
9
+ - Maps to your existing "Lamp-Bottom" unit
10
+
11
+ 2. **Blue LED** (Node 3, Unit 30, ID: 798)
12
+ - Estimated power: 50W
13
+ - Maps to your existing "Blue LED" unit
14
+
15
+ ## Testing Steps
16
+
17
+ ### **Step 1: Start the Server (in Debug Mode)**
18
+
19
+ 1. Open VS Code debugger
20
+ 2. Set breakpoints if needed:
21
+ - `server/smartapp.ts` line ~165 (setupWebSocketServers)
22
+ - `server/smartapp.ts` line ~230 (handleDeviceMessage)
23
+ 3. Run the debugger with testHB.ts configuration
24
+ - Or: `ts-node testHB.ts` in terminal
25
+
26
+ The server should start on port 5002 (from your config)
27
+
28
+ ### **Step 2: Verify Server Started**
29
+
30
+ You should see log messages:
31
+ ```
32
+ ✓ WebSocket server 0 set up on path /devices
33
+ ✓ WebApp - Listening on port 5002
34
+ ✓ mDNS service registered
35
+ ```
36
+
37
+ ### **Step 3: Test WebSocket Connection**
38
+
39
+ In a **separate terminal**, run the test client:
40
+
41
+ ```bash
42
+ # Using mDNS name (recommended)
43
+ ts-node testWS.ts ws://duotecno-gateway.local/devices
44
+
45
+ # Or specify IP address if needed
46
+ ts-node testWS.ts ws://192.168.0.99/devices
47
+ ```
48
+
49
+ ### **Step 4: Expected Test Client Output**
50
+
51
+ ```
52
+ ╔════════════════════════════════════════════════════════════════════╗
53
+ ║ WebSocket Device Control Test Client ║
54
+ ║ Press Ctrl+C to exit ║
55
+ ╚════════════════════════════════════════════════════════════════════╝
56
+
57
+ 🔌 Connecting to WebSocket server: ws://duotecno-gateway.local/devices
58
+ ✅ Connected to WebSocket server
59
+
60
+ 📊 Received 2 device(s):
61
+ ════════════════════════════════════════════════════════════════════════
62
+ ID | Name | Power(W) | Current(A) | Voltage(V) | Relay | Measured
63
+ ────────────────────────────────────────────────────────────────────────
64
+ 802 | Test Lamp | 0.0 | 0.00 | 230.0 | 🔴 OFF | 📝
65
+ 798 | Blue LED | 0.0 | 0.00 | 230.0 | 🔴 OFF | 📝
66
+ ════════════════════════════════════════════════════════════════════════
67
+
68
+ ⏱️ Sending keep-alive poll...
69
+
70
+ 🎲 Sending random control commands:
71
+ → Test Lamp (node=3, unit=34, id=802): 🟢 ON
72
+ → Blue LED (node=3, unit=30, id=798): 🟢 ON
73
+
74
+ 📊 Received 2 device(s):
75
+ ════════════════════════════════════════════════════════════════════════
76
+ ID | Name | Power(W) | Current(A) | Voltage(V) | Relay | Measured
77
+ ────────────────────────────────────────────────────────────────────────
78
+ 802 | Test Lamp | 100.0 | 0.43 | 230.0 | 🟢 ON | 📝
79
+ 798 | Blue LED | 50.0 | 0.22 | 230.0 | 🟢 ON | 📝
80
+ ════════════════════════════════════════════════════════════════════════
81
+ ```
82
+
83
+ Notice:
84
+ - Power goes to estimated value (100W, 50W) when relay is ON
85
+ - Power goes to 0 when relay is OFF
86
+ - Current is calculated (Power / 230V)
87
+ - Measured flag shows 📝 (estimated) not 📊 (measured)
88
+
89
+ ### **Step 5: Test Web UI (Optional)**
90
+
91
+ 1. Open browser: `http://duotecno-gateway.local/devices`
92
+ 2. You should see the 2 test devices listed
93
+ 3. Click a device to edit:
94
+ - Change name
95
+ - Change power source (P1, Shelly, Smappee, or Non-measured)
96
+ - Change estimated power
97
+ - Save changes
98
+
99
+ ### **Step 6: Test Manual WebSocket Commands**
100
+
101
+ You can also test manually using a WebSocket client like `wscat`:
102
+
103
+ ```bash
104
+ # Install wscat if needed
105
+ npm install -g wscat
106
+
107
+ # Connect using mDNS name
108
+ wscat -c ws://duotecno-gateway.local/devices
109
+
110
+ # You'll receive device list immediately
111
+
112
+ # Send keep-alive (poll)
113
+ []
114
+
115
+ # Turn device ON
116
+ [{"id": 802, "relay": true}]
117
+
118
+ # Turn device OFF
119
+ [{"id": 802, "relay": false}]
120
+
121
+ # Control multiple devices
122
+ [{"id": 802, "relay": true}, {"id": 798, "relay": false}]
123
+ ```
124
+
125
+ ## What to Look For
126
+
127
+ ### **✅ Success Indicators:**
128
+
129
+ 1. **WebSocket connects** without errors
130
+ 2. **Device list received** with correct IDs (802, 798)
131
+ 3. **Relay control works** - devices turn on/off
132
+ 4. **Power values update** - shows estimated power when ON, 0 when OFF
133
+ 5. **Test client runs** for 30+ seconds without errors
134
+ 6. **Random commands sent** every 10-15 seconds
135
+
136
+ ### **❌ Common Issues:**
137
+
138
+ 1. **Connection refused**
139
+ - Server not running
140
+ - Wrong port (use 5002 from config)
141
+ - Check firewall
142
+
143
+ 2. **No devices received**
144
+ - Check config.json saved correctly
145
+ - Check server logs for device initialization
146
+ - Verify devices array is not empty
147
+
148
+ 3. **Relay control doesn't work**
149
+ - Master not connected (192.168.0.97:5001)
150
+ - Node/Unit don't exist
151
+ - Check server logs for "Node X not found" errors
152
+
153
+ 4. **Power always 0**
154
+ - estimatedPower not set in config
155
+ - powerSource not "none"
156
+ - Check device configuration
157
+
158
+ ## Debugging
159
+
160
+ ### **VS Code Debugger Breakpoints:**
161
+
162
+ Set breakpoints at:
163
+ - `setupWebSocketServers()` - Verify WebSocket server created
164
+ - `handleDeviceMessage()` - See incoming commands
165
+ - `setDeviceRelay()` - Check relay control logic
166
+ - `getDeviceList()` - Verify device data calculation
167
+
168
+ ### **Check Server Logs:**
169
+
170
+ Look for these messages:
171
+ ```
172
+ "WebSocket server 0 set up on path /devices"
173
+ "WebSocket client connected on server 0"
174
+ "Setting device 802 (node=3, unit=34) to true"
175
+ "Init 2 Devices -> add units"
176
+ ```
177
+
178
+ ### **Common Debug Scenarios:**
179
+
180
+ 1. **Devices not initialized:**
181
+ ```
182
+ "** error ** missing device unit: 0x3/0x22 **"
183
+ ```
184
+ → Unit doesn't exist in master
185
+
186
+ 2. **WebSocket connection fails:**
187
+ ```
188
+ "WebSocket error on server 0: ..."
189
+ ```
190
+ → Check port, network, or code issues
191
+
192
+ 3. **Invalid messages:**
193
+ ```
194
+ "Invalid WebSocket message: ..."
195
+ ```
196
+ → Check message format (must be JSON array)
197
+
198
+ ## Next Steps After Testing
199
+
200
+ Once everything works:
201
+ 1. ✅ Confirm device control works
202
+ 2. ✅ Verify power measurements (estimated)
203
+ 3. 🔄 Add real power source (Smappee/P1/Shelly)
204
+ 4. 🔄 Configure power channels
205
+ 5. 🔄 Test with real measurements
206
+ 6. 🔄 Then proceed with Module refactoring
207
+
208
+ ## Quick Commands
209
+
210
+ ```bash
211
+ # Terminal 1: Start server
212
+ ts-node testHB.ts
213
+
214
+ # Terminal 2: Run test client
215
+ ts-node testWS.ts ws://duotecno-gateway.local/devices
216
+
217
+ # Press Ctrl+C in either terminal to stop
218
+ ```
219
+
220
+ Good luck! 🚀