I’m currently working on a workaround to detect the current ‘state’ (speed + lights on/off) by using a power socket (Fibaro Wall Plug) and use the power consumption as an indicator.
Using power consumption as a feedback loop to detect the current state. This enables commands like ‘light off’ and 'speed 2’.
Demo usage:
Parameters:
Novy sub-flow:
The flow:
[
{
"id": "5214c7eb.a9eec8",
"type": "subflow",
"name": "Novy",
"info": "",
"category": "home",
"in": [
{
"x": 340,
"y": 260,
"wires": [
{
"id": "b1cee3c0.5f502"
},
{
"id": "bf340da6.5928"
},
{
"id": "1fa70423.9c331c"
},
{
"id": "d564c8ec.19bd78"
}
]
}
],
"out": [
{
"x": 800,
"y": 520,
"wires": [
{
"id": "95aa2615.a397b8",
"port": 0
}
]
}
],
"env": [
{
"name": "off_watt",
"type": "num",
"value": "0",
"ui": {
"icon": "font-awesome/fa-bolt",
"label": {
"en-US": "OFF (Watt)"
},
"type": "input",
"opts": {
"types": [
"num",
"env"
]
}
}
},
{
"name": "light_watt",
"type": "num",
"value": "11",
"ui": {
"icon": "font-awesome/fa-bolt",
"label": {
"en-US": "LIGHT ON (Watt)"
},
"type": "input",
"opts": {
"types": [
"num",
"env"
]
}
}
},
{
"name": "speed1_watt",
"type": "num",
"value": "6",
"ui": {
"icon": "font-awesome/fa-bolt",
"label": {
"en-US": "SPEED 1 (Watt | light off)"
},
"type": "input",
"opts": {
"types": [
"num",
"env"
]
}
}
},
{
"name": "speed2_watt",
"type": "num",
"value": "26",
"ui": {
"icon": "font-awesome/fa-bolt",
"label": {
"en-US": "SPEED 2 (Watt | light off)"
},
"type": "input",
"opts": {
"types": [
"num",
"env"
]
}
}
},
{
"name": "speed3_watt",
"type": "num",
"value": "56",
"ui": {
"icon": "font-awesome/fa-bolt",
"label": {
"en-US": "SPEED 3 (Watt | light off)"
},
"type": "input",
"opts": {
"types": [
"num",
"env"
]
}
}
},
{
"name": "speed4_watt",
"type": "num",
"value": "147",
"ui": {
"icon": "font-awesome/fa-bolt",
"label": {
"en-US": "SPEED 4 (Watt | light off)"
},
"type": "input",
"opts": {
"types": [
"num",
"env"
]
}
}
}
],
"color": "#E2D96E",
"icon": "font-awesome/fa-snowflake-o",
"status": {
"x": 800,
"y": 580,
"wires": [
{
"id": "192dbed9.1821a1",
"port": 0
}
]
}
},
{
"id": "8c30b2cd.42fc5",
"type": "rfx-fan-out",
"z": "5214c7eb.a9eec8",
"name": "Novy Fan",
"port": "15853799.477678",
"topicSource": "node",
"topic": "NOVY/0",
"x": 840,
"y": 260,
"wires": []
},
{
"id": "ddf6f65c.b83698",
"type": "rfx-lights-out",
"z": "5214c7eb.a9eec8",
"name": "Novy Light",
"port": "15853799.477678",
"topicSource": "node",
"retransmit": "none",
"retransmitInterval": 20,
"topic": "NOVY/0",
"x": 850,
"y": 180,
"wires": []
},
{
"id": "b1cee3c0.5f502",
"type": "switch",
"z": "5214c7eb.a9eec8",
"name": "light",
"property": "topic",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "toggle",
"vt": "str"
},
{
"t": "eq",
"v": "light",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 2,
"x": 490,
"y": 180,
"wires": [
[
"24d9675.2028698"
],
[
"24d9675.2028698"
]
]
},
{
"id": "bf340da6.5928",
"type": "switch",
"z": "5214c7eb.a9eec8",
"name": "power",
"property": "topic",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "power",
"vt": "str"
},
{
"t": "eq",
"v": "on",
"vt": "str"
},
{
"t": "eq",
"v": "off",
"vt": "str"
},
{
"t": "eq",
"v": "time",
"vt": "str"
},
{
"t": "eq",
"v": "speed",
"vt": "str"
},
{
"t": "eq",
"v": "timeout",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 6,
"x": 490,
"y": 260,
"wires": [
[
"3cd5c918.4865b6"
],
[
"3cd5c918.4865b6"
],
[
"3cd5c918.4865b6"
],
[
"3cd5c918.4865b6"
],
[
"3cd5c918.4865b6"
],
[
"3cd5c918.4865b6"
]
]
},
{
"id": "1fa70423.9c331c",
"type": "switch",
"z": "5214c7eb.a9eec8",
"name": "speed",
"property": "topic",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "+",
"vt": "str"
},
{
"t": "eq",
"v": "-",
"vt": "str"
},
{
"t": "eq",
"v": "speed",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 3,
"x": 490,
"y": 340,
"wires": [
[
"c9fb97ee.fdb3f8"
],
[
"c9fb97ee.fdb3f8"
],
[
"c9fb97ee.fdb3f8"
]
]
},
{
"id": "d564c8ec.19bd78",
"type": "switch",
"z": "5214c7eb.a9eec8",
"name": "wattage",
"property": "topic",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "power_consumption",
"vt": "str"
},
{
"t": "eq",
"v": "energy",
"vt": "str"
},
{
"t": "eq",
"v": "wattage",
"vt": "str"
},
{
"t": "eq",
"v": "watt",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 4,
"x": 500,
"y": 400,
"wires": [
[
"6b35cb0d.870e04"
],
[
"6b35cb0d.870e04"
],
[
"6b35cb0d.870e04"
],
[
"6b35cb0d.870e04"
]
]
},
{
"id": "24d9675.2028698",
"type": "function",
"z": "5214c7eb.a9eec8",
"name": "state",
"func": "let _light = flow.get('novy_light') || false;\n\nif(msg.payload === undefined) {\n msg.payload = !_light;\n}\n\nif(_light != msg.payload) {\n return { payload: 'toggle', state: _light};\n}",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 650,
"y": 180,
"wires": [
[
"ddf6f65c.b83698"
]
]
},
{
"id": "3cd5c918.4865b6",
"type": "function",
"z": "5214c7eb.a9eec8",
"name": "state",
"func": "const OFF_DELAY = 1000; // wait xx ms before sending the second power signal to completely turn off\n\nlet _on = flow.get('novy_on') || false;\n\n// discard ongoing speed changes\nflow.set('novy_target_speed', 0);\n\nif(msg.topic === 'speed') {\n if(msg.payload === 0){\n msg.topic = 'off';\n } else {\n return; // skip, handled by 'speed' command \n }\n}\n\nlet command;\nswitch(msg.topic) {\n case 'power':\n command = 'power';\n break;\n case 'time':\n command = 'time';\n break;\n case 'on':\n if(!_on) command = 'power';\n break;\n case 'off':\n if(_on) {\n command = 'power';\n setTimeout(() => node.send({payload: 'power'}), OFF_DELAY);\n }\n break;\n case 'timeout':\n if(_on) command = 'power';\n break;\n}\n\nif(command) {\n return { payload: command };\n}",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 650,
"y": 260,
"wires": [
[
"8c30b2cd.42fc5"
]
]
},
{
"id": "c9fb97ee.fdb3f8",
"type": "function",
"z": "5214c7eb.a9eec8",
"name": "state",
"func": "let _speed = flow.get('novy_speed') || 0;\n\nfunction setSpeed(value) {\n \n if(value === 'power') {\n value = 4;\n }\n \n // NOTE: target_speed is handled in a seperate interval process\n flow.set('novy_target_speed', value); \n \n // NOTE: speed 0 is handled by 'power' command\n if(!value) return;\n\n let dir = Math.sign(value - _speed);\n switch(dir) {\n case -1:\n return '-';\n case 1:\n return '+';\n case 0:\n // nothing\n break;\n }\n}\n\nlet command;\nswitch(msg.topic) {\n case '+':\n command = '+';\n flow.set('novy_target_speed', 0); \n break;\n case '-':\n command = '-';\n flow.set('novy_target_speed', 0); \n break;\n case 'speed':\n command = setSpeed(msg.payload);\n break;\n}\n\nif(command) {\n return { payload: command };\n}",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 650,
"y": 340,
"wires": [
[
"8c30b2cd.42fc5"
]
]
},
{
"id": "24b70ba4.0da8e4",
"type": "link in",
"z": "5214c7eb.a9eec8",
"name": "speed",
"links": [
"c95406c1.06d4e8"
],
"x": 344,
"y": 340,
"wires": [
[
"1fa70423.9c331c"
]
]
},
{
"id": "6b35cb0d.870e04",
"type": "function",
"z": "5214c7eb.a9eec8",
"name": "detect state",
"func": "if(Number.isNaN(msg.payload)) return;\n\n// from Setup\nconst CONFIG = context.get(\"config\");\nconst MAP = context.get(\"map\");\nconst VALUES = context.get(\"values\");\n\n// get current state from context\nlet previous = {\n light: flow.get('novy_light'),\n on: flow.get('novy_on'),\n speed: flow.get('novy_speed'),\n targetSpeed: flow.get('novy_target_speed')\n};\nlet state = {\n light: previous.light,\n on: previous.on,\n speed: previous.speed,\n targetSpeed: previous.targetSpeed\n};\n\n// fetch closest wattage\nlet _power = msg.payload;\nvar closest = VALUES.reduce((prev, curr) => Math.abs(curr - _power) < Math.abs(prev - _power) ? curr : prev);\nvar detected = MAP[closest];\n\n// update state\nstate.on = (detected.speed > 0) || detected.light;\nstate.speed = detected.speed;\nstate.light = detected.light;\n\n// update context\nflow.set('novy_on', state.on);\nflow.set('novy_speed', state.speed);\nflow.set('novy_light', state.light);\n\n// forward states\nlet changes = Object.keys(state).find(key => state[key] != previous[key]);\nif(changes) {\n return {\n payload: { \n previous: previous, \n state: state,\n detected: detected,\n power: _power\n } \n };\n}",
"outputs": 1,
"noerr": 0,
"initialize": "// Code added here will be run once\n// whenever the node is deployed.\n\nconst CONFIG = {\n OFF: env.get('off_watt'),\n LIGHT: env.get('light_watt'),\n SPEED1: env.get('speed1_watt'),\n SPEED2: env.get('speed2_watt'),\n SPEED3: env.get('speed3_watt'),\n SPEED4: env.get('speed4_watt')\n};\n\n// create wattage => state mappping\nconst MAP = {};\nMAP[CONFIG.OFF] = { speed: 0, light: false };\nMAP[CONFIG.LIGHT] = { speed: 0, light: true };\nMAP[CONFIG.SPEED1] = { speed: 1, light: false };\nMAP[CONFIG.SPEED2] = { speed: 2, light: false };\nMAP[CONFIG.SPEED3] = { speed: 3, light: false };\nMAP[CONFIG.SPEED4] = { speed: 4, light: false };\nMAP[CONFIG.SPEED1 + CONFIG.LIGHT] = { speed: 1, light: true };\nMAP[CONFIG.SPEED2 + CONFIG.LIGHT] = { speed: 2, light: true };\nMAP[CONFIG.SPEED3 + CONFIG.LIGHT] = { speed: 3, light: true };\nMAP[CONFIG.SPEED4 + CONFIG.LIGHT] = { speed: 4, light: true };\n\n// sort all wattage values\nconst VALUES = Object.keys(MAP);\nVALUES.sort();\n\n// store on context\ncontext.set(\"config\", CONFIG);\ncontext.set(\"map\", MAP);\ncontext.set(\"values\", VALUES);",
"finalize": "",
"x": 670,
"y": 400,
"wires": [
[
"165e3c9f.f525c3"
]
]
},
{
"id": "c2098d1b.54cb4",
"type": "function",
"z": "5214c7eb.a9eec8",
"name": "target speed reached?",
"func": "const RESET_DELAY = 0; // wait xx ms before resetting target speed to account for small power fluctuations\n\nfunction reset(){\n let targetSpeed = flow.get('novy_target_speed');\n if(targetSpeed){\n let speed = flow.get('novy_speed');\n if(speed == targetSpeed) {\n flow.set('novy_target_speed', 0);\n }\n }\n}\n\n// speed changed?\nif(msg.payload.state.targetSpeed && msg.payload.previous.speed != msg.payload.state.speed) {\n if(msg.payload.state.speed == msg.payload.state.targetSpeed){\n if(RESET_DELAY){\n setTimeout(() => reset(), RESET_DELAY);\n } else {\n flow.set('novy_target_speed', 0);\n }\n } else {\n return { topic:'speed', payload: msg.payload.state.targetSpeed }; \n }\n}\n",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 540,
"y": 460,
"wires": [
[
"c95406c1.06d4e8"
]
]
},
{
"id": "c95406c1.06d4e8",
"type": "link out",
"z": "5214c7eb.a9eec8",
"name": "",
"links": [
"24b70ba4.0da8e4"
],
"x": 795,
"y": 460,
"wires": []
},
{
"id": "a50ae15d.09d35",
"type": "comment",
"z": "5214c7eb.a9eec8",
"name": "change speed if target speed not reached",
"info": "",
"x": 980,
"y": 460,
"wires": []
},
{
"id": "8c3ae02e.2263c",
"type": "link in",
"z": "5214c7eb.a9eec8",
"name": "state change",
"links": [
"165e3c9f.f525c3"
],
"x": 344,
"y": 460,
"wires": [
[
"c2098d1b.54cb4",
"95aa2615.a397b8"
]
]
},
{
"id": "165e3c9f.f525c3",
"type": "link out",
"z": "5214c7eb.a9eec8",
"name": "",
"links": [
"8c3ae02e.2263c"
],
"x": 795,
"y": 400,
"wires": []
},
{
"id": "941b3a1d.6b3bf8",
"type": "comment",
"z": "5214c7eb.a9eec8",
"name": "state change",
"info": "",
"x": 890,
"y": 400,
"wires": []
},
{
"id": "a696284a.004968",
"type": "comment",
"z": "5214c7eb.a9eec8",
"name": "speed",
"info": "",
"x": 279,
"y": 340,
"wires": []
},
{
"id": "4e2144fa.0a7e3c",
"type": "comment",
"z": "5214c7eb.a9eec8",
"name": "state",
"info": "",
"x": 279,
"y": 460,
"wires": []
},
{
"id": "95aa2615.a397b8",
"type": "change",
"z": "5214c7eb.a9eec8",
"name": "state",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "payload.state",
"tot": "msg"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 490,
"y": 520,
"wires": [
[
"192dbed9.1821a1"
]
]
},
{
"id": "192dbed9.1821a1",
"type": "template",
"z": "5214c7eb.a9eec8",
"name": "status",
"field": "payload",
"fieldType": "msg",
"format": "handlebars",
"syntax": "mustache",
"template": "On: {{ payload.light }}, Light: {{ payload.light }}, Speed: {{ payload.speed }}",
"output": "str",
"x": 650,
"y": 580,
"wires": [
[]
]
},
{
"id": "15853799.477678",
"type": "rfxtrx-port",
"z": "",
"port": "/dev/ttyUSB1",
"enableDebug": true,
"rfyVenetianMode": "EU"
},
{
"id": "9d69f6bb.905698",
"type": "tab",
"label": "Novy - TEST",
"disabled": false,
"info": ""
},
{
"id": "1d1677d4.34c178",
"type": "inject",
"z": "9d69f6bb.905698",
"name": "light: toggle",
"props": [
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "toggle",
"x": 310,
"y": 140,
"wires": [
[
"fe64e11c.7f6fc"
]
]
},
{
"id": "d5521b.29984de8",
"type": "inject",
"z": "9d69f6bb.905698",
"name": "speed 0",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "speed",
"payload": "0",
"payloadType": "num",
"x": 330,
"y": 440,
"wires": [
[
"fe64e11c.7f6fc"
]
]
},
{
"id": "b608f70.c466408",
"type": "inject",
"z": "9d69f6bb.905698",
"name": "light: on",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "light",
"payload": "true",
"payloadType": "bool",
"x": 330,
"y": 180,
"wires": [
[
"fe64e11c.7f6fc"
]
]
},
{
"id": "e6c14e6f.f1e0d",
"type": "inject",
"z": "9d69f6bb.905698",
"name": "light: off",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "light",
"payload": "false",
"payloadType": "bool",
"x": 330,
"y": 220,
"wires": [
[
"fe64e11c.7f6fc"
]
]
},
{
"id": "6b25fe7c.98e4",
"type": "server-state-changed",
"z": "9d69f6bb.905698",
"name": "power consumption",
"server": "5223992.6e8ce68",
"version": 1,
"exposeToHomeAssistant": false,
"haConfig": [
{
"property": "name",
"value": ""
},
{
"property": "icon",
"value": ""
}
],
"entityidfilter": "sensor.afzuigkap_power",
"entityidfiltertype": "exact",
"outputinitially": true,
"state_type": "num",
"haltifstate": "",
"halt_if_type": "str",
"halt_if_compare": "is",
"outputs": 1,
"output_only_on_state_change": true,
"x": 170,
"y": 80,
"wires": [
[
"1c92ff4d.118a61"
]
]
},
{
"id": "7a232eab.2c6d1",
"type": "inject",
"z": "9d69f6bb.905698",
"name": "time",
"props": [
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "time",
"x": 330,
"y": 320,
"wires": [
[
"fe64e11c.7f6fc"
]
]
},
{
"id": "33f6357.e87eeca",
"type": "inject",
"z": "9d69f6bb.905698",
"name": "power",
"props": [
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "power",
"payloadType": "str",
"x": 330,
"y": 280,
"wires": [
[
"fe64e11c.7f6fc"
]
]
},
{
"id": "5b73a4cf.68389c",
"type": "inject",
"z": "9d69f6bb.905698",
"name": "on",
"props": [
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "on",
"x": 330,
"y": 360,
"wires": [
[
"fe64e11c.7f6fc"
]
]
},
{
"id": "9b545fdd.1227d",
"type": "inject",
"z": "9d69f6bb.905698",
"name": "off",
"props": [
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "off",
"payloadType": "str",
"x": 330,
"y": 400,
"wires": [
[
"fe64e11c.7f6fc"
]
]
},
{
"id": "a2a3ed7b.78cab",
"type": "inject",
"z": "9d69f6bb.905698",
"name": "speed 1",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "speed",
"payload": "1",
"payloadType": "num",
"x": 330,
"y": 540,
"wires": [
[
"fe64e11c.7f6fc"
]
]
},
{
"id": "14675dd3.1b9502",
"type": "inject",
"z": "9d69f6bb.905698",
"name": "speed 2",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "speed",
"payload": "2",
"payloadType": "num",
"x": 330,
"y": 580,
"wires": [
[
"fe64e11c.7f6fc"
]
]
},
{
"id": "81d5de1b.bd263",
"type": "inject",
"z": "9d69f6bb.905698",
"name": "speed 3",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "speed",
"payload": "3",
"payloadType": "num",
"x": 330,
"y": 620,
"wires": [
[
"fe64e11c.7f6fc"
]
]
},
{
"id": "f2593ecf.e596b",
"type": "inject",
"z": "9d69f6bb.905698",
"name": "speed 4",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "speed",
"payload": "4",
"payloadType": "num",
"x": 330,
"y": 660,
"wires": [
[
"fe64e11c.7f6fc"
]
]
},
{
"id": "41d2c43.c2d2f3c",
"type": "inject",
"z": "9d69f6bb.905698",
"name": "+",
"props": [
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "+",
"x": 330,
"y": 700,
"wires": [
[
"fe64e11c.7f6fc"
]
]
},
{
"id": "a783bc35.aa60f",
"type": "inject",
"z": "9d69f6bb.905698",
"name": "-",
"props": [
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "-",
"x": 330,
"y": 740,
"wires": [
[
"fe64e11c.7f6fc"
]
]
},
{
"id": "eaada55e.289bd8",
"type": "inject",
"z": "9d69f6bb.905698",
"name": "timeout",
"props": [
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "timeout",
"x": 330,
"y": 480,
"wires": [
[
"fe64e11c.7f6fc"
]
]
},
{
"id": "fe64e11c.7f6fc",
"type": "subflow:5214c7eb.a9eec8",
"z": "9d69f6bb.905698",
"name": "",
"env": [
{
"name": "light_watt",
"value": "12",
"type": "num"
},
{
"name": "speed1_watt",
"value": "7",
"type": "num"
},
{
"name": "speed2_watt",
"value": "27",
"type": "num"
},
{
"name": "speed3_watt",
"value": "58",
"type": "num"
},
{
"name": "speed4_watt",
"value": "140",
"type": "num"
},
{
"name": "deviceId",
"value": "1",
"type": "num"
}
],
"x": 570,
"y": 80,
"wires": [
[
"7500bf8d.4f405"
]
]
},
{
"id": "7500bf8d.4f405",
"type": "debug",
"z": "9d69f6bb.905698",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 730,
"y": 80,
"wires": []
},
{
"id": "1c92ff4d.118a61",
"type": "change",
"z": "9d69f6bb.905698",
"name": "topic",
"rules": [
{
"t": "set",
"p": "topic",
"pt": "msg",
"to": "power_consumption",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 330,
"y": 80,
"wires": [
[
"fe64e11c.7f6fc"
]
]
},
{
"id": "5223992.6e8ce68",
"type": "server",
"z": "",
"name": "Home Assistant",
"legacy": false,
"addon": false,
"rejectUnauthorizedCerts": false,
"ha_boolean": "y|yes|true|on|home|open",
"connectionDelay": true,
"cacheJson": true
}
]
In my appdaemon app I have a state machine which mimicks the behaviour of the hood. I keep it in sync by swiching off using the “-” command, and each time I do this I add a few “-” extra. This is sure to switch the hood off, even if it would be out of sync with my state machine.
The only tricky part is the boost function, which is time limited. For this I also have a timer in my state machine which reduces the fan speed a few seconds before the internal fan timer would. That way I keep things in sync.
Downside of this is that you can no longer use the original remote. That is why in my code you will also find references to a Tradfri remote, which I use to control the hood and the lighting in the kitchen.
All that just to be able to control the hood with my smartphone .
Thomas.
@thomas-be That looks like the same route I took with my Novy Homey driver. That one even listens to the button presses of the remote and updates the state when a button press is detected. This way the remote can still be used. It also tracks the boost function timeout.
Using that driver, the remote button-presses were not detected at all times and therefore the state was out-of-sync regulary. Furthermore the hood itself has some buttons and I’ve got a novy induction cooking unit with buttons to control the hood. I want to keep using all of these. By measuring the power consumption I’ve got a quite precise indication of the actual state of the hood.
The current implementation actually works quite well:
pressing some random buttons in HA & on the remote
When I activate the ‘movie’ or ‘sleep’ scene, I also want to turn of the hood lights.
And I also measure the power consumption of the induction cooking unit and automatically set the speed of the hood.
That makes a lot of sense! Fortunately for me I don’t have a Novy cooking unit and the hood so high up it is out of reach .
I wonder if you could also use the power consumption to track the status of the filters . In my Zehnder ventilation unit I can keep track of a lot of parameters and there I see a clear correlation between airflow; power and the status of the filter. That said, in the hood you have no information on the flow, so not sure you can go on power alone.
Thomas
so how to integrate that into HA using the standard RFXTRX integration and the RFXCOMM 433XL ?
You can’t. The standard integration does not support fan entities so you cannot use it. That is why we all have our own version of “hacked” solutions, either through Node Red or AppDaemon.
Thomas
The BroadLink RM pro app does support fan entities, and it’s designed to record and replay RF commands. That’s why I wonder if anyone has ever tried a broadlink device, which are pretty cheap compared with the RFXTRX ones.
Is there any technical reason why RFXTRX can control this hood but other RF remotes can’t?
ah! so it is HA that is the problem, not RFXTRX? (makes sense, as i can control the Novy hood using RFXTRX via the RFXmgr application on windows).
Yes, indeed. Control of ventilation units & hoods is not implemented in Home Assistant in any way. This could be remedied by allowing HA to simulate the buttons on the remote, but currently this is not available.
Thomas
Potentially. However, in this case there is no state feedback from the hood I doubt you will get this into an official integration. A starting point could be my appdaemon app novy_hood/novy.py at master · tnagels/novy_hood (github.com), but this has Tradfri control integrated. I use this as you can’t combine HA control and direct control with the hood remote. If there is enough interest I’m willing to look into making this more universally usable.
Thomas
Hi all,
I would like to add my Novy hood through HA - Node-red…
17/02/2021 02:56:48:631= Fan command: 08 17 0B 3B 00 00 03 04 00
Packettype = Fan
subtype = Novy
Sequence nbr = 59
ID = 4
Command = Light
Signal level = +13 dBm !
17/02/2021 02:56:48:990= 0402013B00
Packettype = Receiver/Transmitter Message
subtype = Transmitter Response
Sequence nbr = 59
response = ACK, data correct transmitted
What do I need more / need to do to get this working in Node-RED?
Anybody still here…,?
Hi Harrie,
Is it easy to remove the hood? We have a new kitchen, but it is impossible to reach the outlet without removing (the entire?) hood…
Is it easy to do?
Important update
With the new version of the integration it has become extrmely easy to control your Novy hood. Only downside is that it would not be shown as a fan, but you can use services to send the command.
The service is rfxtrx:send
And the payloads that work for me are:
08170B010000020100
: on/off toggle
08170B010000020200
: increase speed
08170B010000020300
: decrease speed
08170B010000020400
: toggle light
It was not THAT easy
This is how I got it to work:
I’m using an RFXTRX XL and I installed firmware 1044. I also needed to enable the ‘fan’ protocol.
Using the RFXmanager I found that the commands for my Novy hood were slightly different. These work for me:
power 08170B090000000100
up 08170B0C0000000200
down 08170B0D0000000300
Light 08170B0E0000000400
Finally I used the Blueprint and Template from @thomas-be
The only thing missing is the Light button. I created this script and can use that to toggle the lights on/off:
alias: novy_lights
sequence:
- service: rfxtrx.send
data:
event: 08170B090000000400
mode: single
Good that you could make it work! Some thoughts on your experience:
- The first few steps you mention I already did before, when I used my AppDaemon app. So that’s why I did not put them in the explanation.
- The reason your commands differ from mine is that you can “link” the hood to the remote which changes a part of the command. This is so you can use multiple hoods independently in the same home. This is why I made it configurable in the blueprint (forgot to mention that).
- I did not add the light because my hood does not have the built-in lights.
I agree, it may not be “extremely easy”, but it for sure is a lot simpler than when you had to use an AppDaemon app to communicate directly with the RFXtrx!
Thanks for the reply.
Would it be possible to add the Lights to the Blueprint?
Would be really cool if the light would get added to the blueprint indeed.
Can anyone help with linking the command_up to a button on a remote? I obiously can send the command from the button, but that results in an out of sync with the fan template situation.
Could you send me the RAW codes?
Thx!