MWD5 WiFi thermostat (OJ Electronics/Microtemp)

My bad, I thought I had to snif my own API key. By now I used the given API key and get an error in nodered logs: [https-node:Request: Thermostats] JSON parse error.
And home assistant logs gave me this info:
Logger: nodered.microtemp
Source: components/system_log/init.py:256
First occurred: 19:59:37 (21 occurrences)
Last logged: 20:17:43

Microtemp: Error logging in {“SessionId”:"",“UserName”:"",“ErrorCode”:1}
Microtemp: Error getting thermostats

I am using the SWATT app. Might that be the issue, of is there something else I’m doing wrong?

Thanks for your help.

Good work.
I also has a few of these thermostat’s I would like to integrate.
I see that OpenHab has made a binding/add-on
Maybe there is some tip on how they have made the integration.

Source:

The login works. In the “Get thermostats and save to Flow” I get an error on the “Request thermostats” part:

18-11-2022 13:56:20[node: Request: Thermostats]
msg : string[16]
“JSON parse error”

Looks like there is something not correct in “prepare request” but I don’t know where to start.

Is there someone who can help me out. I just copied the info from @oppigard and change the necessary information.

Thanks in advance.

Hi,
This is very exciting topic and it looks like Kjetil has done a great job. I have a couple of these devices and just started exploring NodeRed in HA in general. Tested the logon and it works ok.
I wonder, is it possible to download this flow somewhere so I can start testing ?

Thanks in advance !

just copy the code from post 9 and import it in Node-Red. That worked for me.

Hi. Thanks for the fast respons.
I am not able to see or download anything under post 9, other then a picture.
Under the picture I can see this :
Processing: mwd5.json…

Hi, my bad, was post 8 by @oppigard

[{"id":"e5cd67040e53b56a","type":"tab","label":"MWD5","disabled":false,"info":"","env":[]},{"id":"2ba18eae40896b3b","type":"group","z":"e5cd67040e53b56a","name":"Login and store SessionId and APIKEY in Flow","style":{"fill":"#ffefbf","label":true,"stroke":"#7f7f7f","color":"#000000"},"nodes":["1ffa9c7da6ccaa2b","2127bb1ed287df05","76275a21cbc9f43d","75c78c7a5580bb99","063b4810e9852abf"],"x":34,"y":39,"w":1252,"h":142},{"id":"8def1125549333c4","type":"group","z":"e5cd67040e53b56a","name":"Read from Home Assistant MQTT and POST changes","style":{"label":true,"stroke":"#7f7f7f","fill":"#ffefbf","color":"#000000"},"nodes":["55aadf15091fdd4b","ecea2bfb3d635156","bde8b48880cb1331","5fab4e02dad20af8","269ea38a85d9af1c","e8dbe311940e0050","c23c6453199e0cac","203f3350f8a481e2"],"x":34,"y":639,"w":1252,"h":182},{"id":"4da1903fdbd168f9","type":"group","z":"e5cd67040e53b56a","name":"Write to Home Assistant MQTT","style":{"label":true,"stroke":"#7f7f7f","fill":"#ffefbf","color":"#000000"},"nodes":["dba22a6916fd8802","aba352db94bc86e6","b3d16ebb934249cc","f11c0b4741440f31","a861bef0d9237d6c","458003326807e0c7","0347430d9ca2c764","5722e943d6b61d5d"],"x":34,"y":399,"w":1252,"h":202},{"id":"d999bc4cbdf72bf6","type":"group","z":"e5cd67040e53b56a","name":"Get thermostats and save to Flow","style":{"label":true,"stroke":"#7f7f7f","fill":"#ffefbf","color":"#000000"},"nodes":["703108d59eacbd77","3a656d46d0ece598","98e75c3e4f46b59d","607139dccfa05e8b","33528644d6e4f08a","81774dfea51ed57d","39eef15aebcb3f75","c23cbf64548598ef"],"x":34,"y":219,"w":1252,"h":142},{"id":"5977aa28e19bbcbc","type":"group","z":"e5cd67040e53b56a","name":"Get energy consumption close to the end of every hour, store value in Flow context, and trigger MQTT publish","style":{"fill":"#ffefbf","label":true,"color":"#000000"},"nodes":["dc1d3ed427eb8816","9cc614397a8c5d43","b4256525e75ba6d6","e36c6d336f5c1a37","8404d450b5dcbf56","c8a3f44c6f2ff481","f4c2b227b66898e7","a50bc3dc7f8d1bbd","1c59d95d702dd376","c9d0b83c8a972d32"],"x":34,"y":859,"w":1252,"h":162},{"id":"e36c6d336f5c1a37","type":"inject","z":"e5cd67040e53b56a","g":"5977aa28e19bbcbc","name":"Start","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":130,"y":920,"wires":[[]]},{"id":"1ffa9c7da6ccaa2b","type":"https-node","z":"e5cd67040e53b56a","g":"2ba18eae40896b3b","name":"Request: Login","method":"use","ret":"obj","url":"","authorized":false,"agent":false,"x":560,"y":120,"wires":[["75c78c7a5580bb99"]]},{"id":"2127bb1ed287df05","type":"change","z":"e5cd67040e53b56a","g":"2ba18eae40896b3b","name":"Store SessionId and APIKEY","rules":[{"t":"set","p":"SessionId","pt":"flow","to":"payload.SessionId","tot":"msg"},{"t":"set","p":"APIKEY","pt":"flow","to":"APIKEY","tot":"msg"},{"t":"set","p":"Login_Time","pt":"flow","to":"$now()","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":1140,"y":80,"wires":[[]]},{"id":"76275a21cbc9f43d","type":"inject","z":"e5cd67040e53b56a","g":"2ba18eae40896b3b","name":"Login at startup and every hour","props":[{"p":"UserName","v":"user","vt":"str"},{"p":"Password","v":"pass","vt":"str"},{"p":"APIKEY","v":"f219aab4-9ac0-4343-8422-b72203e2fac9","vt":"str"},{"p":"url","v":"https://owd5-mh015-app.ojelectronics.com/api/UserProfile/SignIn","vt":"str"},{"p":"method","v":"POST","vt":"str"},{"p":"headers","v":"{'Content-Type': 'application/json'}","vt":"jsonata"},{"p":"payload"}],"repeat":"3600","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"{\t   \"APIKEY\": msg.APIKEY,\t   \"UserName\": msg.UserName,\t   \"Password\": msg.Password,\t   \"ClientSWVersion\": 1,\t   \"CustomerId\": 15\t}","payloadType":"jsonata","x":210,"y":120,"wires":[["1ffa9c7da6ccaa2b"]]},{"id":"703108d59eacbd77","type":"inject","z":"e5cd67040e53b56a","g":"d999bc4cbdf72bf6","name":"Get Thermostats every 1min","props":[{"p":"payload"}],"repeat":"60","crontab":"","once":true,"onceDelay":"20","topic":"","payload":"","payloadType":"date","x":210,"y":260,"wires":[["3a656d46d0ece598"]]},{"id":"3a656d46d0ece598","type":"change","z":"e5cd67040e53b56a","g":"d999bc4cbdf72bf6","name":"Prepare Request","rules":[{"t":"set","p":"url","pt":"msg","to":"'https://owd5-mh015-app.ojelectronics.com/api/Group/GroupContents?sessionid=' &\t $flowContext('SessionId') &\t '&APIKEY=' & $flowContext('APIKEY')","tot":"jsonata"},{"t":"set","p":"method","pt":"msg","to":"GET","tot":"str"},{"t":"set","p":"headers","pt":"msg","to":"{'Content-Type': 'application/json'}","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":470,"y":300,"wires":[["98e75c3e4f46b59d"]]},{"id":"98e75c3e4f46b59d","type":"https-node","z":"e5cd67040e53b56a","g":"d999bc4cbdf72bf6","name":"Request: Thermostats","method":"use","ret":"obj","url":"","authorized":false,"agent":false,"x":700,"y":300,"wires":[["81774dfea51ed57d"]]},{"id":"607139dccfa05e8b","type":"function","z":"e5cd67040e53b56a","g":"d999bc4cbdf72bf6","name":"Store in Flow","func":"\nif (typeof flow.get(\"Load\") !== 'object') {\n    flow.set(`Load`, {})\n}\nvar load = flow.get(\"Load\")\n\nlet groups = Object.values(msg.payload.GroupContents)\n\nfor (var k = 0; k < groups.length; k++) {\n    let data = groups[k].Thermostats\n    for (var i = 0; i < data.length; i++) {\n        var serial = data[i].SerialNumber\n        flow.set(`Thermostats.${serial}`, data[i])\n        if (serial in load) {\n            // do nothing\n        }\n        else {\n            flow.set(`Load.${serial}`, { load: 0 })\n        }\n    }\n}\n\nreturn { payload: 'ok' }","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1130,"y":260,"wires":[["c23cbf64548598ef"]]},{"id":"dba22a6916fd8802","type":"mqtt out","z":"e5cd67040e53b56a","g":"4da1903fdbd168f9","name":"MQTT","topic":"","qos":"","retain":"","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"8c21765b4658e89b","x":1210,"y":520,"wires":[]},{"id":"aba352db94bc86e6","type":"function","z":"e5cd67040e53b56a","g":"4da1903fdbd168f9","name":"Prepare MQTT Config","func":"var output = []\nfor (var serial in flow.get('Thermostats')) {\n    var t = flow.get(`Thermostats.${serial}`)\n    var name = t.ThermostatName\n    var device = {\n        'identifiers': serial,\n        'name': name,\n        'manufacturer': 'Micromatic',\n        'model': 'Microtemp MWD5'\n    }\n    output.push(\n        {\n            'topic': `homeassistant/climate/microtemp/${serial}_thermostat/config`,\n            'payload': {\n                'name': name,\n                'unique_id': serial,\n                'device': device,\n                'modes': [\n                    'heat'\n                ],\n                'preset_modes': [\n                    'Schedule',\n                    'Comfort',\n                    'Boost',\n                    'Eco'\n                ],\n                'min_temp': t.MinSetpoint /100,\n                'max_temp': t.MaxSetpoint /100,\n                'current_temperature_topic': `homeassistant/sensor/microtemp/${serial}_current/state`,\n                'mode_state_topic': `homeassistant/sensor/microtemp/${serial}_mode/state`,\n                'mode_command_topic': `homeassistant/sensor/microtemp/${serial}_mode/set`,\n                'temperature_state_topic': `homeassistant/sensor/microtemp/${serial}_temperature/state`,\n                'temperature_command_topic': `homeassistant/sensor/microtemp/${serial}_temperature/set`,\n                'preset_mode_state_topic': `homeassistant/sensor/microtemp/${serial}_preset/state`,\n                'preset_mode_command_topic': `homeassistant/sensor/microtemp/${serial}_preset/set`,\n                'precision': 0.5,\n                'temp_step': 0.5\n\n            }\n        },\n        {\n            'topic': `homeassistant/sensor/microtemp/${serial}_room/config`,\n            'payload': {\n                'name': name + ' Room Temperature',\n                'unique_id': serial + 'room',\n                'device': device,\n                'device_class': 'temperature',\n                'unit_of_measurement': '°C',\n                'state_class': 'measurement',\n                'state_topic': `homeassistant/sensor/microtemp/${serial}_room/state`\n            }\n        },\n        {\n            'topic': `homeassistant/sensor/microtemp/${serial}_floor/config`,\n            'payload': {\n                'name': name + ' Floor Temperature',\n                'unique_id': serial + 'floor',\n                'device': device,\n                'device_class': 'temperature',\n                'icon': 'mdi:heating-coil',\n                'unit_of_measurement': '°C',\n                'state_class': 'measurement',\n                'state_topic': `homeassistant/sensor/microtemp/${serial}_floor/state`\n            }\n        },\n        {\n            'topic': `homeassistant/sensor/microtemp/${serial}_power/config`,\n            'payload': {\n                'name': name + ' Power',\n                'unique_id': serial + ' power',\n                'device': device,\n                'device_class': 'power',\n                'unit_of_measurement': 'W',\n                'state_class': 'measurement',\n                'state_topic': `homeassistant/sensor/microtemp/${serial}_power/state`\n            }\n        },\n        {\n            'topic': `homeassistant/sensor/microtemp/${serial}_energy/config`,\n            'payload': {\n                'name': name + ' Energy',\n                'unique_id': serial + ' energy',\n                'device': device,\n                'device_class': 'energy',\n                'unit_of_measurement': 'kWh',\n                'state_class': 'total',\n                'state_topic': `homeassistant/sensor/microtemp/${serial}_energy/state`\n            }\n        },\n        {\n            'topic': `homeassistant/sensor/microtemp/${serial}_mainsensor/config`,\n            'payload': {\n                'name': name + ' Main Temperature Sensor',\n                'unique_id': serial + ' main',\n                'device': device,\n                'state_topic': `homeassistant/sensor/microtemp/${serial}_mainsensor/state`\n            }\n        },\n        {\n            'topic': `homeassistant/number/microtemp/${serial}_load/config`,\n            'payload': {\n                'name': name + ' Connected Load',\n                'unique_id': serial + ' connected_load',\n                'device': device,\n                'entity_category': 'config',\n                'mode': 'box',\n                'min': 0,\n                'max': 10000,\n                'unit_of_measurement': 'W',\n                'command_topic': `homeassistant/number/microtemp/${serial}_load/set`,\n                'state_topic': `homeassistant/number/microtemp/${serial}_load/state`\n            }\n        }\n    )\n}\n\n\nreturn {'payload': output};","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":480,"y":560,"wires":[["b3d16ebb934249cc"]]},{"id":"b3d16ebb934249cc","type":"splitter","z":"e5cd67040e53b56a","g":"4da1903fdbd168f9","name":"Loop through Topics","property":"payload","x":720,"y":520,"wires":[["f11c0b4741440f31"]]},{"id":"f11c0b4741440f31","type":"change","z":"e5cd67040e53b56a","g":"4da1903fdbd168f9","name":"Extract MQTT Topic & Payload","rules":[{"t":"set","p":"topic","pt":"msg","to":"payload.topic","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"payload.payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":990,"y":520,"wires":[["dba22a6916fd8802"]]},{"id":"a861bef0d9237d6c","type":"inject","z":"e5cd67040e53b56a","g":"4da1903fdbd168f9","name":"Create MQTT Topics every hour","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"3600","crontab":"","once":true,"onceDelay":"120","topic":"","payload":"","payloadType":"date","x":220,"y":560,"wires":[["aba352db94bc86e6"]]},{"id":"55aadf15091fdd4b","type":"mqtt in","z":"e5cd67040e53b56a","g":"8def1125549333c4","name":"","topic":"homeassistant/+/microtemp/+/set","qos":"2","datatype":"auto-detect","broker":"8c21765b4658e89b","nl":false,"rap":true,"rh":0,"inputs":0,"x":190,"y":720,"wires":[["ecea2bfb3d635156"]]},{"id":"ecea2bfb3d635156","type":"function","z":"e5cd67040e53b56a","g":"8def1125549333c4","name":"Prepare POST request","func":"var topic = msg.topic.split(\"/\")[3].split('_')\nvar serial = topic[0]\nvar task = topic[1]\nvar name = flow.get(`Thermostats.${serial}.ThermostatName`)\nvar apikey = flow.get(\"APIKEY\")\nvar session = flow.get(\"SessionId\")\nvar url = `https://owd5-mh015-app.ojelectronics.com/api/Thermostat/UpdateThermostat?sessionid=${session}`\nvar presets = {\n    'Schedule': 1,\n    'Comfort': 2,\n    'None': 3,\n    'Vacation': 4,\n    'Boost': 8,\n    'Eco': 9\n}\n\nvar payload = {\n    \"APIKEY\": apikey,\n    \"ThermostatID\": serial,\n    \"SetThermostat\": {\n        \"SerialNumber\": serial,\n        \"ThermostatName\": name\n    }\n}\n\nnode.warn(task);\n\nvar mqtt_topic\n\nif (task == 'temperature') {\n    payload.SetThermostat.ManualModeSetpoint = msg.payload * 100\n    payload.SetThermostat.RegulationMode = 3\n    mqtt_topic = `homeassistant/sensor/microtemp/${serial}_temperature/state`\n}\nelse if (task == 'preset') {\n    let preset = presets[msg.payload]\n    payload.SetThermostat.RegulationMode = preset\n    if (preset == 3) {\n        var temperature\n        if (typeof flow.get(`Thermostats.${serial}.ManualModeSetpoint`) == 'undefined' ||\n            flow.get(`Thermostats.${serial}.ManualModeSetpoint`) == 0)\n        {\n            flow.set(`Thermostats.${serial}.ManualModeSetpoint`, 2000)\n        }\n        payload.SetThermostat.ManualModeSetpoint = flow.get(`Thermostats.${serial}.ManualModeSetpoint`)\n    }\n    mqtt_topic = `homeassistant/sensor/microtemp/${serial}_preset/state`\n}\nelse if (task == 'load') {\n    flow.set(`Load.${serial}`, msg.payload)\n    mqtt_topic = \"homeassistant/number/microtemp/${serial}_load/state\"\n}\n\nelse {\n    return null;\n}\n\nreturn [\n    {\n        \"method\": \"POST\",\n        \"url\": url,\n        \"payload\": payload,\n        \"json\": payload\n    },\n    {\n        'topic': mqtt_topic,\n        'payload': msg.payload\n    }\n];","outputs":2,"noerr":0,"initialize":"","finalize":"","libs":[],"x":500,"y":720,"wires":[["bde8b48880cb1331"],["e8dbe311940e0050"]]},{"id":"bde8b48880cb1331","type":"https-node","z":"e5cd67040e53b56a","g":"8def1125549333c4","name":"Post changes","method":"use","ret":"obj","url":"","authorized":false,"agent":false,"x":780,"y":700,"wires":[["5fab4e02dad20af8"]]},{"id":"458003326807e0c7","type":"inject","z":"e5cd67040e53b56a","g":"4da1903fdbd168f9","name":"Manual Send Values","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":170,"y":480,"wires":[["0347430d9ca2c764"]]},{"id":"0347430d9ca2c764","type":"function","z":"e5cd67040e53b56a","g":"4da1903fdbd168f9","name":"Prepare MQTT Values","func":"var presets = {\n    1: 'Schedule',\n    2: 'Comfort',\n    3: 'None',\n    4: 'Vacation',\n    8: 'Boost',\n    9: 'Eco'\n}\nvar sensor_appl = {\n    1: 'Room with floor protection',\n    3: 'Floor',\n    4: 'Room'\n}\nfunction getScheduleTemp() {\n    var date1 = new Date()\n    var date2 = new Date()\n    var day = date1.getDay()\n    var yesterday\n    if (day == 0) {\n        day = 6\n        yesterday = 5\n    }\n    else if (day == 1) {\n        day = 0\n        yesterday = 6\n    }\n    else {\n        day = day - 1\n        yesterday = day - 1\n    }\n    var chosen\n    var temperature = 0\n    var schedule = flow.get(`Thermostats.299386.Schedule.Days.${day}.Events`)\n    for (var i = schedule.length - 1; i >= 0; i--) {\n        if (schedule[i].Active) {\n            let time = schedule[i].Clock.split(\":\")\n            date2.setHours(time[0], time[1], time[2])\n            if (date1 > date2) {\n                temperature = schedule[i].Temperature\n                chosen = \"Valgt dag: \" + day + \" - Valgt program: \" + i\n                break\n            }\n        }\n    }\n    if (temperature == 0) {\n        schedule = flow.get(`Thermostats.299386.Schedule.Days.${yesterday}.Events`)\n        for (var i = schedule.length - 1; i >= 0; i--) {\n            if (schedule[i].Active) {\n                temperature = schedule[i].Temperature\n                chosen = \"Valgt dag: \" + yesterday + \" - Valgt program: \" + i\n                break\n            }\n        }\n    }\n    return temperature\n}\nvar output = []\nfor (var serial in flow.get('Thermostats')) {\n    var t = flow.get(`Thermostats.${serial}`)\n    var load = flow.get(`Load.${serial}`)\n    var current\n    var power\n\n    if (t.Heating) power = load\n    else power = 0\n    \n    var main_sensor\n\n    if (t.SensorAppl == 3) {\n        current = t.FloorTemperature / 100\n        main_sensor = 'Floor'\n    }\n    else {\n        current = t.RoomTemperature / 100\n        main_sensor = 'Room'\n    }\n\n    var temperature\n    if (t.RegulationMode == 1) temperature = getScheduleTemp()\n    else if (t.RegulationMode == 2) temperature = t.ComfortSetpoint\n    else if (t.RegulationMode == 4) temperature = t.VacationTemperature\n    else temperature = t.ManualModeSetpoint\n    if (temperature == 0) temperature = 20\n    else temperature = temperature / 100\n\n    var energy = 0\n    if (typeof flow.get(`EnergyConsumption.${serial}`) === 'number') {\n        energy = flow.get(`EnergyConsumption.${serial}`)\n    }\n\n    output.push(\n        {\n            topic: `homeassistant/sensor/microtemp/${serial}_current/state`,\n            payload: current\n        },\n        {\n            topic: `homeassistant/sensor/microtemp/${serial}_mode/state`,\n            payload: 'heat'\n        },\n        {\n            topic: `homeassistant/sensor/microtemp/${serial}_temperature/state`,\n            payload: temperature\n        },\n        {\n            topic: `homeassistant/sensor/microtemp/${serial}_preset/state`,\n            payload: presets[t.RegulationMode]\n        },\n        {\n            topic: `homeassistant/sensor/microtemp/${serial}_room/state`,\n            payload: t.RoomTemperature / 100\n        },\n        {\n            topic: `homeassistant/sensor/microtemp/${serial}_floor/state`,\n            payload: t.FloorTemperature / 100\n        },\n        {\n            topic: `homeassistant/sensor/microtemp/${serial}_power/state`,\n            payload: power\n        },\n        {\n            topic: `homeassistant/sensor/microtemp/${serial}_energy/state`,\n            payload: energy\n        },\n        {\n            topic: `homeassistant/sensor/microtemp/${serial}_mainsensor/state`,\n            payload: main_sensor\n        },\n        {\n            topic: `homeassistant/number/microtemp/${serial}_load/state`,\n            payload: load\n        }\n    )\n}\n\n\nreturn {'payload': output};","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":480,"y":480,"wires":[["b3d16ebb934249cc"]]},{"id":"5fab4e02dad20af8","type":"switch","z":"e5cd67040e53b56a","g":"8def1125549333c4","name":"ErrorCode","property":"payload.ErrorCode","propertyType":"msg","rules":[{"t":"eq","v":"0","vt":"num"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":970,"y":700,"wires":[["269ea38a85d9af1c"],["203f3350f8a481e2"]]},{"id":"269ea38a85d9af1c","type":"link out","z":"e5cd67040e53b56a","g":"8def1125549333c4","name":"Update after change","mode":"link","links":["33528644d6e4f08a"],"x":1165,"y":680,"wires":[]},{"id":"33528644d6e4f08a","type":"link in","z":"e5cd67040e53b56a","g":"d999bc4cbdf72bf6","name":"Update after change","links":["269ea38a85d9af1c","8a3dbab986b48680"],"x":315,"y":320,"wires":[["3a656d46d0ece598"]]},{"id":"81774dfea51ed57d","type":"switch","z":"e5cd67040e53b56a","g":"d999bc4cbdf72bf6","name":"ErrorCode","property":"payload.ErrorCode","propertyType":"msg","rules":[{"t":"eq","v":"0","vt":"num"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":910,"y":300,"wires":[["607139dccfa05e8b"],["39eef15aebcb3f75"]]},{"id":"75c78c7a5580bb99","type":"switch","z":"e5cd67040e53b56a","g":"2ba18eae40896b3b","name":"ErrorCode","property":"payload.ErrorCode","propertyType":"msg","rules":[{"t":"eq","v":"0","vt":"num"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":830,"y":120,"wires":[["2127bb1ed287df05"],["063b4810e9852abf"]]},{"id":"063b4810e9852abf","type":"api-call-service","z":"e5cd67040e53b56a","g":"2ba18eae40896b3b","name":"Login error","server":"dd079736.bfc538","version":5,"debugenabled":false,"domain":"system_log","service":"write","areaId":[],"deviceId":[],"entityId":[],"data":"{\t   \"message\": \"Microtemp: Error logging in   \" & payload,\t   \"logger\": \"nodered.microtemp\"\t}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"last","x":1090,"y":140,"wires":[[]]},{"id":"39eef15aebcb3f75","type":"api-call-service","z":"e5cd67040e53b56a","g":"d999bc4cbdf72bf6","name":"GET error","server":"dd079736.bfc538","version":5,"debugenabled":false,"domain":"system_log","service":"write","areaId":[],"deviceId":[],"entityId":[],"data":"{\t   \"message\": \"Microtemp: Error getting thermostats   \" & payload,\t   \"logger\": \"nodered.microtemp\"\t}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"last","x":1120,"y":320,"wires":[[]]},{"id":"5722e943d6b61d5d","type":"link in","z":"e5cd67040e53b56a","g":"4da1903fdbd168f9","name":"Send data after update","links":["c23cbf64548598ef","1c59d95d702dd376"],"x":285,"y":440,"wires":[["0347430d9ca2c764"]]},{"id":"c23cbf64548598ef","type":"link out","z":"e5cd67040e53b56a","g":"d999bc4cbdf72bf6","name":"Send data after update","mode":"link","links":["5722e943d6b61d5d"],"x":1245,"y":260,"wires":[]},{"id":"e8dbe311940e0050","type":"mqtt out","z":"e5cd67040e53b56a","g":"8def1125549333c4","name":"MQTT","topic":"","qos":"","retain":"","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"8c21765b4658e89b","x":750,"y":780,"wires":[]},{"id":"c23c6453199e0cac","type":"comment","z":"e5cd67040e53b56a","g":"8def1125549333c4","name":"Extra MQTT node: Update Home Assistant right away to prevent confusion ->","info":"","x":370,"y":780,"wires":[]},{"id":"dc1d3ed427eb8816","type":"change","z":"e5cd67040e53b56a","g":"5977aa28e19bbcbc","name":"Prepare Request","rules":[{"t":"set","p":"url","pt":"msg","to":"'https://owd5-mh015-app.ojelectronics.com/api/EnergyUsage/GetEnergyUsage?sessionid=' &\t $flowContext('SessionId') &\t '&APIKEY=' & $flowContext('APIKEY')","tot":"jsonata"},{"t":"set","p":"method","pt":"msg","to":"POST","tot":"str"},{"t":"set","p":"headers","pt":"msg","to":"{'Content-Type': 'application/json'}","tot":"jsonata"},{"t":"set","p":"serial","pt":"msg","to":"payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"{\t   \"APIKEY\": $flowContext('APIKEY'),\t   \"DateTime\": $moment().add(1, \"days\").format(\"YYYY-MM-DD[T]HH:mm:ss\"),\t   \"History\": 0,\t   \"ThermostatID\": $.payload,\t   \"ViewType\": 2\t}","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":330,"y":980,"wires":[["9cc614397a8c5d43"]]},{"id":"9cc614397a8c5d43","type":"https-node","z":"e5cd67040e53b56a","g":"5977aa28e19bbcbc","name":"Request: Consumption","method":"use","ret":"obj","url":"","authorized":false,"agent":false,"x":560,"y":980,"wires":[["b4256525e75ba6d6"]]},{"id":"b4256525e75ba6d6","type":"switch","z":"e5cd67040e53b56a","g":"5977aa28e19bbcbc","name":"ErrorCode","property":"payload.ErrorCode","propertyType":"msg","rules":[{"t":"eq","v":"0","vt":"num"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":810,"y":980,"wires":[["8404d450b5dcbf56"],["c8a3f44c6f2ff481"]]},{"id":"8404d450b5dcbf56","type":"function","z":"e5cd67040e53b56a","g":"5977aa28e19bbcbc","name":"Store in Flow","func":"if (typeof flow.get(`EnergyConsumption`) !== 'object') {\n    flow.set(`EnergyConsumption`, {})\n}\n\nvar value = msg.payload.EnergyUsage[0].Usage[0].EnergyKWattHour\nvar serial = msg.serial\nflow.set(`EnergyConsumption.${serial}`, value)\n\nreturn { value: value, serial: serial }","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1070,"y":900,"wires":[["1c59d95d702dd376"]]},{"id":"203f3350f8a481e2","type":"api-call-service","z":"e5cd67040e53b56a","g":"8def1125549333c4","name":"Set error","server":"dd079736.bfc538","version":5,"debugenabled":false,"domain":"system_log","service":"write","areaId":[],"deviceId":[],"entityId":[],"data":"{\t   \"message\": \"Microtemp: Error writing changes to thermostats   \" & payload,\t   \"logger\": \"nodered.microtemp\"\t}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"last","x":1200,"y":760,"wires":[[]]},{"id":"c8a3f44c6f2ff481","type":"api-call-service","z":"e5cd67040e53b56a","g":"5977aa28e19bbcbc","name":"GetEnergy error","server":"dd079736.bfc538","version":5,"debugenabled":false,"domain":"system_log","service":"write","areaId":[],"deviceId":[],"entityId":[],"data":"{\t   \"message\": \"Microtemp: Error getting energy consumption   \" & payload,\t   \"logger\": \"nodered.microtemp\"\t}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"last","x":1080,"y":980,"wires":[[]]},{"id":"f4c2b227b66898e7","type":"function","z":"e5cd67040e53b56a","g":"5977aa28e19bbcbc","name":"Get Thermostats","func":"var thermostats = []\nfor (var serial in flow.get('Thermostats')) {\n    thermostats.push(serial)\n}\n\nreturn { thermostats: thermostats };","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":330,"y":920,"wires":[["a50bc3dc7f8d1bbd"]]},{"id":"a50bc3dc7f8d1bbd","type":"splitter","z":"e5cd67040e53b56a","g":"5977aa28e19bbcbc","name":"Loop Thermostats","property":"thermostats","x":550,"y":920,"wires":[["dc1d3ed427eb8816"]]},{"id":"1c59d95d702dd376","type":"link out","z":"e5cd67040e53b56a","g":"5977aa28e19bbcbc","name":"Send data after update","mode":"link","links":["5722e943d6b61d5d"],"x":1245,"y":900,"wires":[]},{"id":"c9d0b83c8a972d32","type":"crontinject","z":"e5cd67040e53b56a","g":"5977aa28e19bbcbc","name":"Start","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","crontiMethod":"onCrontime","crontiArgs":"[\"58 * * * *\"]","x":130,"y":920,"wires":[["f4c2b227b66898e7"]]},{"id":"8c21765b4658e89b","type":"mqtt-broker","name":"HASS","broker":"localhost","port":"1883","clientid":"","autoConnect":true,"usetls":false,"protocolVersion":"4","keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","birthMsg":{},"closeTopic":"","closeQos":"0","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willPayload":"","willMsg":{},"userProps":"","sessionExpiry":""},{"id":"dd079736.bfc538","type":"server","name":"Home Assistant","version":4,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":"30","areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m"}]

Hi 0xi3 !
Thank you for the information.
Just startet to edit the flow with my own data.

Nice, please let me know if you get an error too while requesting thermostats:

18-11-2022 13:56:20[node: Request: Thermostats]
msg : string[16]
“JSON parse error”

And if you are able to fix it, I like to know how, because I’m struggling with it many evenings already😰

I’m trying to solve this with Python, but I get a 403-response to the login-request:
The requested resource does not support http method ‘GET’.
Negotiate works, Connect returns 400 The ConnectionId is in the incorrect format.

Any idea what I could try to get it working?

Hi.
I do not get this error from this Request Thermostats node.
Used a debug node to watch the result.
23.11.2022, 20:13:47[node: debug 2]
msg.payload : Object
{ GroupContents: array[1], ErrorCode: 0 }

Strange, There must be something wrong on my side. These are the prepare request node settings:

And below the settings there are in the Request Thermostat node. Can you confirm those are right?

image

Hi. The order in my i different. It is not easy to see what your picture shows i details.
image

Have you checked in Flow context that you have SessionId set to a string after you log in?
Should change each time you log in.
Can you hook up a debug-node to the output of your “Request Thermostats” node?
Make the debug node show the entire msg object.

You need to use https, seems like you are using http?
Do you have a git repo for this project? I’m very interested in getting these thermostats working as a hacs integration without nodered/mqtt, and if I have som spare time I would be happy to contribute.

Hi oppigard,

thanks a lot for your node red flow. I can confirm this flow (including the changes from this post) works as expected.

I’m using this flow with Schluter DITRA HEAT E R WIFI. Therefore, I needed to set customerId = 3 in the login node.

Now, we have everything together that we could also create a full integration if someone would have time for it.

Again, thanks a lot.

Hi,
I hacked something together that works for me. My method was to dissasemble the android app and extract the api info from there. The code for the custom integration is extremely ugly, so it should be rewritten by someone more knowledgeable. I will probably not have time to do it right in the near future.
User/pass is hardcoded in python.
It uses the climate (integration I guess it’s called).
It will poll the sensors every 1 minute or sooner if you change a setting.
It supports setting Manual+Temp/Auto/FrostProtect/Boost (boost duration fixed in python script).

If anyone is interested I can share my work.

Sounds great! Would be fantastic if you can share, and perhaps someone here can tidy up the code.

Here you go:

Let me know if this works for you

2 Likes

Got this error

`Error while setting up mwd5 platform for climate

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 281, in _async_setup_platform
    await asyncio.shield(task)
  File "/usr/local/lib/python3.10/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/config/custom_components/mwd5/climate.py", line 325, in setup_platform
    thermos = t.getThermoInfo()
  File "/config/custom_components/mwd5/climate.py", line 203, in getThermoInfo
    for group in data["GroupContents"]:
TypeError: 'NoneType' object is not subscriptable
`