MWD5 WiFi thermostat (OJ Electronics/Microtemp)

I’ve had the Microtemp MWD5 WiFi thermostat for a couple of years, and a while back I successfully sniffed the communication between the mobile app and the cloud.
It communicates with HTTP POST/GET with json data, and seems simple to create an integration for it.

Is there a similar thermostat integration that would be easier to modify than start from scratch?

I’ve postponed this task for almost a year now, so if anyone else wants to have a go, use my notes below. The main priority is to control it in manual mode and get energy usage from it.

Signin:

POST https://owd5-mh015-app.ojelectronics.com/api/UserProfile/SignIn
{
    "APIKEY": "f219aab4-9ac0-4343-8422-b72203e2fac9",
    "ClientSWVersion": 1,
    "CustomerId": 111,
    "Password": "password",
    "UserName": "username"
}

HTTP/1.1 200 OK
{
    "ErrorCode": 0,
    "SessionId": "fXL6a_GsEkODSl0xFXtXRA",
    "UserName": "username"
}

GetGroupContents:

GET https://owd5-mh015-app.ojelectronics.com/api/Group/GroupContents?sessionid=fXL6a_GsEkODSl0xFXtXRA&APIKEY=f219aab4-9ac0-4343-8422-b72203e2fac9

HTTP/1.1 200 OK

{
    "ErrorCode": 0,
    "GroupContents": [
        {
            "Action": 0,
            "BoostEndTime": "1900-01-01T00:00:00",
            "ComfortEndTime": "1900-01-01T00:00:00",
            "ComfortSetpoint": 2300,
            "FrostProtectionTemperature": 500,
            "GroupId": 17953,
            "GroupName": "Bad",
            "LastPrimaryModeIsAuto": true,
            "ManualModeSetpoint": 2197,
            "RegulationMode": 1,
            "Schedule": {
                "Days": [
                    {
                        "Events": [
                            {
                                "Active": true,
                                "Clock": "06:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 0,
                                "Temperature": 2208
                            },
                            {
                                "Active": true,
                                "Clock": "07:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 1,
                                "Temperature": 1818
                            },
                            {
                                "Active": false,
                                "Clock": "12:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 2,
                                "Temperature": 2000
                            },
                            {
                                "Active": false,
                                "Clock": "13:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 3,
                                "Temperature": 1500
                            },
                            {
                                "Active": true,
                                "Clock": "15:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 4,
                                "Temperature": 2175
                            },
                            {
                                "Active": true,
                                "Clock": "23:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 5,
                                "Temperature": 1814
                            }
                        ],
                        "WeekDayGrpNo": 1
                    },
                    {
                        "Events": [
                            {
                                "Active": true,
                                "Clock": "06:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 0,
                                "Temperature": 2208
                            },
                            {
                                "Active": true,
                                "Clock": "07:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 1,
                                "Temperature": 1818
                            },
                            {
                                "Active": false,
                                "Clock": "12:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 2,
                                "Temperature": 2000
                            },
                            {
                                "Active": false,
                                "Clock": "13:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 3,
                                "Temperature": 1500
                            },
                            {
                                "Active": true,
                                "Clock": "15:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 4,
                                "Temperature": 2175
                            },
                            {
                                "Active": true,
                                "Clock": "23:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 5,
                                "Temperature": 1814
                            }
                        ],
                        "WeekDayGrpNo": 2
                    },
                    {
                        "Events": [
                            {
                                "Active": true,
                                "Clock": "06:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 0,
                                "Temperature": 2208
                            },
                            {
                                "Active": true,
                                "Clock": "07:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 1,
                                "Temperature": 1818
                            },
                            {
                                "Active": false,
                                "Clock": "12:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 2,
                                "Temperature": 2000
                            },
                            {
                                "Active": false,
                                "Clock": "13:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 3,
                                "Temperature": 1500
                            },
                            {
                                "Active": true,
                                "Clock": "15:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 4,
                                "Temperature": 2175
                            },
                            {
                                "Active": true,
                                "Clock": "23:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 5,
                                "Temperature": 1814
                            }
                        ],
                        "WeekDayGrpNo": 3
                    },
                    {
                        "Events": [
                            {
                                "Active": true,
                                "Clock": "06:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 0,
                                "Temperature": 2208
                            },
                            {
                                "Active": true,
                                "Clock": "07:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 1,
                                "Temperature": 1818
                            },
                            {
                                "Active": false,
                                "Clock": "12:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 2,
                                "Temperature": 2000
                            },
                            {
                                "Active": false,
                                "Clock": "13:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 3,
                                "Temperature": 1500
                            },
                            {
                                "Active": true,
                                "Clock": "15:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 4,
                                "Temperature": 2175
                            },
                            {
                                "Active": true,
                                "Clock": "23:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 5,
                                "Temperature": 1814
                            }
                        ],
                        "WeekDayGrpNo": 4
                    },
                    {
                        "Events": [
                            {
                                "Active": true,
                                "Clock": "06:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 0,
                                "Temperature": 2208
                            },
                            {
                                "Active": true,
                                "Clock": "07:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 1,
                                "Temperature": 1818
                            },
                            {
                                "Active": false,
                                "Clock": "12:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 2,
                                "Temperature": 2000
                            },
                            {
                                "Active": false,
                                "Clock": "13:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 3,
                                "Temperature": 1500
                            },
                            {
                                "Active": true,
                                "Clock": "15:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 4,
                                "Temperature": 2175
                            },
                            {
                                "Active": true,
                                "Clock": "23:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 5,
                                "Temperature": 1814
                            }
                        ],
                        "WeekDayGrpNo": 5
                    },
                    {
                        "Events": [
                            {
                                "Active": true,
                                "Clock": "06:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 0,
                                "Temperature": 2197
                            },
                            {
                                "Active": false,
                                "Clock": "09:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 1,
                                "Temperature": 1798
                            },
                            {
                                "Active": false,
                                "Clock": "12:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 2,
                                "Temperature": 2000
                            },
                            {
                                "Active": false,
                                "Clock": "13:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 3,
                                "Temperature": 1500
                            },
                            {
                                "Active": false,
                                "Clock": "17:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 4,
                                "Temperature": 2000
                            },
                            {
                                "Active": true,
                                "Clock": "23:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 5,
                                "Temperature": 1786
                            }
                        ],
                        "WeekDayGrpNo": 6
                    },
                    {
                        "Events": [
                            {
                                "Active": true,
                                "Clock": "06:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 0,
                                "Temperature": 2197
                            },
                            {
                                "Active": false,
                                "Clock": "09:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 1,
                                "Temperature": 1798
                            },
                            {
                                "Active": false,
                                "Clock": "12:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 2,
                                "Temperature": 2000
                            },
                            {
                                "Active": false,
                                "Clock": "13:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 3,
                                "Temperature": 1500
                            },
                            {
                                "Active": false,
                                "Clock": "17:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 4,
                                "Temperature": 2000
                            },
                            {
                                "Active": true,
                                "Clock": "23:00:00",
                                "EventIsOnNextDay": false,
                                "ScheduleType": 5,
                                "Temperature": 1786
                            }
                        ],
                        "WeekDayGrpNo": 7
                    }
                ],
                "ModifiedDueToVerification": false
            },
            "Thermostats": [
                {
                    "Action": 0,
                    "AdaptiveMode": false,
                    "BoostEndTime": "1900-01-01T00:00:00",
                    "ComfortEndTime": "1900-01-01T00:00:00",
                    "ComfortSetpoint": 2300,
                    "CustomerId": 15,
                    "DaylightSaving": false,
                    "DaylightSavingActive": false,
                    "ErrorCode": 0,
                    "FloorTemperature": 2190,
                    "FloorType": 2,
                    "FrostProtectionTemperature": 500,
                    "GroupId": 17953,
                    "GroupName": "Bad",
                    "Heating": false,
                    "Id": 89037,
                    "LastPrimaryModeIsAuto": true,
                    "ManualModeSetpoint": 2679,
                    "MaxSetpoint": 4000,
                    "MinSetpoint": 500,
                    "Online": true,
                    "OpenWindow": false,
                    "RegulationMode": 1,
                    "RoomTemperature": 2317,
                    "SWversion": "1013W212",
                    "Schedule": {
                        Same as Schedule section above, I removed this because of the character limit
                    },
                    "SensorAppl": 3,
                    "SerialNumber": "299386",
                    "ThermostatName": "Gulvvarme",
                    "TimeZone": 3600,
                    "VacationBeginDay": "2017-01-01T00:00:00",
                    "VacationEnabled": false,
                    "VacationEndDay": "2017-01-02T00:00:00",
                    "VacationTemperature": 500
                }
            ],
            "VacationBeginDay": "2016-01-01T00:00:00",
            "VacationEnabled": false,
            "VacationEndDay": "2016-01-01T00:00:00",
            "VacationTemperature": 500
        }
    ]
}

Manual Setpoint:

POST https://owd5-mh015-app.ojelectronics.com/api/Group/UpdateGroup?sessionid=fXL6a_GsEkODSl0xFXtXRA

{
    "APIKEY": "f219aab4-9ac0-4343-8422-b72203e2fac9",
    "SetGroup": {
        "BoostEndTime": "1900-01-01T00:00:00",
        "ComfortEndTime": "1900-01-01T00:00:00",
        "ComfortSetpoint": 2300,
        "ExcludeVacationData": false,
        "GroupId": 17953,
        "GroupName": "Bad",
        "LastPrimaryModeIsAuto": true,
        "ManualModeSetpoint": 2470,
        "RegulationMode": 3,
        "Schedule": {
           I removed this because of the character limit
        },
        "VacationBeginDay": "2016-01-01T00:00:00",
        "VacationEnabled": false,
        "VacationEndDay": "2016-01-01T00:00:00",
        "VacationTemperature": 0
    }
}

HTTP/1.1 200 OK
{
    "ErrorCode": 0
}

Return to plan:

POST https://owd5-mh015-app.ojelectronics.com/api/Group/UpdateGroup?sessionid=fXL6a_GsEkODSl0xFXtXRA

{
    "APIKEY": "f219aab4-9ac0-4343-8422-b72203e2fac9",
    "SetGroup": {
        "BoostEndTime": "1900-01-01T00:00:00",
        "ComfortEndTime": "1900-01-01T00:00:00",
        "ComfortSetpoint": 2300,
        "ExcludeVacationData": false,
        "GroupId": 17953,
        "GroupName": "Bad",
        "LastPrimaryModeIsAuto": true,
        "ManualModeSetpoint": 2470,
        "RegulationMode": 1,
        "Schedule": {
            I removed this because of the character limit
        },
        "VacationBeginDay": "2016-01-01T00:00:00",
        "VacationEnabled": false,
        "VacationEndDay": "2016-01-01T00:00:00",
        "VacationTemperature": 0
    }
}

HTTP/1.1 200 OK
{
    "ErrorCode": 0
}

Boost mode:

POST https://owd5-mh015-app.ojelectronics.com/api/Group/UpdateGroup?sessionid=fXL6a_GsEkODSl0xFXtXRA

{
    "APIKEY": "f219aab4-9ac0-4343-8422-b72203e2fac9",
    "SetGroup": {
        "BoostEndTime": "2021-12-29T17:47:00",
        "ComfortEndTime": "1900-01-01T00:00:00",
        "ComfortSetpoint": 2300,
        "ExcludeVacationData": false,
        "GroupId": 17953,
        "GroupName": "Bad",
        "LastPrimaryModeIsAuto": true,
        "ManualModeSetpoint": 2470,
        "RegulationMode": 8,
        "Schedule": {
            I removed this because of the character limit
        },
        "VacationBeginDay": "2016-01-01T00:00:00",
        "VacationEnabled": false,
        "VacationEndDay": "2016-01-01T00:00:00",
        "VacationTemperature": 0
    }
}

HTTP/1.1 200 OK
{
    "ErrorCode": 0
}

Comfort mode:

POST https://owd5-mh015-app.ojelectronics.com/api/Group/UpdateGroup?sessionid=D0eepWCdFkq6rfiTiNTKCA

{
    "APIKEY": "f219aab4-9ac0-4343-8422-b72203e2fac9",
    "SetGroup": {
        "BoostEndTime": "2021-12-29T17:47:00",
        "ComfortEndTime": "2021-12-29T19:00:00",
        "ComfortSetpoint": 2175,
        "ExcludeVacationData": false,
        "GroupId": 17953,
        "GroupName": "Bad",
        "LastPrimaryModeIsAuto": true,
        "ManualModeSetpoint": 2470,
        "RegulationMode": 2,
        "Schedule": {
            I removed this because of the character limit
        },
        "VacationBeginDay": "2016-01-01T00:00:00",
        "VacationEnabled": false,
        "VacationEndDay": "2016-01-01T00:00:00",
        "VacationTemperature": 0
    }
}

HTTP/1.1 200 OK
{
    "ErrorCode": 0
}

Eco mode:

POST https://owd5-mh015-app.ojelectronics.com/api/Group/UpdateGroup?sessionid=8t1DR49y90SB2XfCVlsshg

{
    "APIKEY": "f219aab4-9ac0-4343-8422-b72203e2fac9",
    "SetGroup": {
        "BoostEndTime": "2021-12-29T17:47:00",
        "ComfortEndTime": "2021-12-29T19:00:00",
        "ComfortSetpoint": 2175,
        "ExcludeVacationData": false,
        "GroupId": 17953,
        "GroupName": "Bad",
        "LastPrimaryModeIsAuto": true,
        "ManualModeSetpoint": 2470,
        "RegulationMode": 9,
        "Schedule": {
            I removed this because of the character limit
        },
        "VacationBeginDay": "2016-01-01T00:00:00",
        "VacationEnabled": false,
        "VacationEndDay": "2016-01-01T00:00:00",
        "VacationTemperature": 0
    }
}

Energy usage:

POST https://owd5-mh015-app.ojelectronics.com/api/EnergyUsage/GetEnergyUsage?sessionid=MniO_4mA8ECJOt3d54Gfwg

Week:
{
    "APIKEY": "f219aab4-9ac0-4343-8422-b72203e2fac9",
    "DateTime": "2021-12-29T17:04:49",
    "History": 0,
    "ThermostatID": "299386",
    "ViewType": 2
}

{
    "EnergyUsage": [
        {
            "Usage": [
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                }
            ]
        }
    ],
    "ErrorCode": 0
}


Month:
{
    "APIKEY": "f219aab4-9ac0-4343-8422-b72203e2fac9",
    "DateTime": "2021-12-29T17:05:33",
    "History": 4,
    "ThermostatID": "299386",
    "ViewType": 2
}

{
    "EnergyUsage": [
        {
            "Usage": [
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                }
            ]
        },
        {
            "Usage": [
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                }
            ]
        },
        {
            "Usage": [
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                }
            ]
        },
        {
            "Usage": [
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                }
            ]
        },
        {
            "Usage": [
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                }
            ]
        }
    ],
    "ErrorCode": 0
}


Year:
{
    "APIKEY": "f219aab4-9ac0-4343-8422-b72203e2fac9",
    "DateTime": "2021-01-29T17:05:48",
    "History": 0,
    "ThermostatID": "299386",
    "ViewType": 4
}

{
    "EnergyUsage": [
        {
            "Usage": [
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                },
                {
                    "EnergyKWattHour": 0.0
                }
            ]
        }
    ],
    "ErrorCode": 0
}

Negotiate (2 steps) (unsure if this is at the start, or if it is needed):

GET https://owd5-mh015-app.ojelectronics.com/ocd5notification/negotiate?clientProtocol=1.3

Response:
{
    "ConnectionId": "7fe6ba31-be25-44cb-ac72-6b62e3ce5ecb",
    "ConnectionTimeout": 110.0,
    "ConnectionToken": "3H5PCkeD1lLHiLvVS0xklpe5apgHYIudkycXcHbUwFv2Qzy/4EFQF8SXwBT7fssqUb4UpnwIGoNsnH63nl1+M/Av2/L3fo/3UinL42Yqphf9Br3fQyeGStSXJ4kirwpc",
    "DisconnectTimeout": 30.0,
    "KeepAliveTimeout": 20.0,
    "LongPollDelay": 0.0,
    "ProtocolVersion": "1.3",
    "TransportConnectTimeout": 5.0,
    "TryWebSockets": true,
    "Url": "/ocd5notification"
}


----

GET https://owd5-mh015-app.ojelectronics.com/ocd5notification/connect?transport=serverSentEvents&connectionToken=3H5PCkeD1lLHiLvVS0xklpe5apgHYIudkycXcHbUwFv2Qzy%2F4EFQF8SXwBT7fssqUb4UpnwIGoNsnH63nl1%2BM%2FAv2%2FL3fo%2F3UinL42Yqphf9Br3fQyeGStSXJ4kirwpc&connectionId=7fe6ba31-be25-44cb-ac72-6b62e3ce5ecb
No response
3 Likes

Would love to see this integration, however I don’t have the coding skills to write it. Happy to help test it though. Even better would be a local offline integration, but that’s probably pushing it.

Just wondering if you have any success with this?
I do have 6 OJ Electronics MWD5 thermostats. I was trying to use Node-Red (http request node) at least to get basic info from thermostats. However I’m not able to get through the authentication phase.
I cannot read “SessionID” from the first sign-in POST response. Most likely it’s related to TLS/SSL certificates in NodeRed and in that 'http request" node, which I don’t know how to setup.

This is how the response look like
image

I’ve not been working on this at all to be honest.
NodeRED was an interesting approach which I haven’t thought of, maybe I’ll give that a go.
I have been playing around with pyscript (from HACS) recently, and I was thinking of writing a pyscript app to interface with the WiFi thermostats, it would at least be something I feel confident in.

@zdenek.masek I testet Node-RED today, and got the login thing working.
You need to download the node-red-contrib-https node.
You can test it by importing my simple login flow:

[
    {
        "id": "11e00fc5a1e0e44c",
        "type": "https-node",
        "z": "923feb3d885b568e",
        "name": "",
        "method": "use",
        "ret": "obj",
        "url": "",
        "authorized": false,
        "agent": false,
        "x": 650,
        "y": 360,
        "wires": [
            [
                "e8e9e70685e66a83",
                "4a90e3f7a408c1e6"
            ]
        ]
    },
    {
        "id": "e8e9e70685e66a83",
        "type": "debug",
        "z": "923feb3d885b568e",
        "name": "debug 1",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 880,
        "y": 360,
        "wires": []
    },
    {
        "id": "d392991e53d0eed6",
        "type": "inject",
        "z": "923feb3d885b568e",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 240,
        "y": 360,
        "wires": [
            [
                "834fdcca9d707a1a"
            ]
        ]
    },
    {
        "id": "834fdcca9d707a1a",
        "type": "change",
        "z": "923feb3d885b568e",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "url",
                "pt": "msg",
                "to": "https://owd5-mh015-app.ojelectronics.com/api/UserProfile/SignIn",
                "tot": "str"
            },
            {
                "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": "payload",
                "pt": "msg",
                "to": "{\"APIKEY\":\"f219aab4-9ac0-4343-8422-b72203e2fac9\",\"UserName\":\"user\",\"ClientSWVersion\":1,\"CustomerId\":15,\"Password\":\"pass\"}",
                "tot": "jsonata"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 440,
        "y": 360,
        "wires": [
            [
                "11e00fc5a1e0e44c"
            ]
        ]
    },
    {
        "id": "4a90e3f7a408c1e6",
        "type": "change",
        "z": "923feb3d885b568e",
        "name": "SessionId",
        "rules": [
            {
                "t": "set",
                "p": "SessionId",
                "pt": "flow",
                "to": "payload.SessionId",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 880,
        "y": 280,
        "wires": [
            []
        ]
    }
]

This sets a flow.SessionId. Since I am completely new to Node-RED I do not know what is considered best practice.
I would appreciate if you shared your final result, as I am keen to learn more about Node-RED.

@oppigard - without any changes on my flow I can see SessionID now. Really don’t know what has changed, but certainly I didn’t update my flow since my last post here.
So, finally I can now read thermostat data and make them visible in the HA. I’m not expert in Node Red and my approach certainly is not the best, but it works.
I’m using MQTT broker and then MQTT sensor in HA.

My test flow:

[{"id":"99d1772b779dadb3","type":"debug","z":"e0263d19a83676e6","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":630,"y":100,"wires":[]},{"id":"d45fab97172ab747","type":"inject","z":"e0263d19a83676e6","name":"","props":[],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":110,"y":260,"wires":[["0f236c45fe4a817a"]]},{"id":"0f236c45fe4a817a","type":"function","z":"e0263d19a83676e6","name":"POST","func":"msg.headers = {}\nmsg.method = \"POST\"\nmsg.url = \"https://owd5-r1099-app.ojelectronics.com/api/UserProfile/SignIn\" ;\n//msg.url = \"https://owd5-mh015-app.ojelectronics.com/api/UserProfile/SignIn\";\nmsg.headers[\"Accept\"] = \"application/json; charset=utf-8\"\n//msg.headers[\"Content-Type\"] = \"application/json; charset=utf-8\"\nmsg.headers[\"Content-Type\"] = \"application/json\"\n//msg.headers[\"Content-Type\"] = \"application/x-www-form-urlencoded\"\nmsg.headers[\"User-Agent\"] = \"Dalvik/2.1.1 (Linux; U; Android 6.0.1; LG-H955 Build/MMB29M)\"\nmsg.headers[\"Host\"] = \"owd5-r1099-app.ojelectronics.com\"\nmsg.headers[\"connection\"] = \"Keep-Alive\"\nmsg.headers[\"Accept-Encoding\"] = \"gzip\"\nmsg.headers[\"Content-Length\"] = \"147\"\n\n\nmsg.payload = {\n//\"id\":\"ID\",\n//\"method\":\"authenticate\",\n//\"params\":\n//{\n\"UserName\":\"username\",\n\"APIKEY\":\"APIKEY\",\n\"Password\":\"password\",\n\"ClientSWVersion\":1,\n\"CustomerId\":99\n};\n//\"jsonrpc\":\"2.0\"\n//};\n\nreturn msg","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":270,"y":260,"wires":[["c3cd1b0b6dd5cb7d","cecedc157612aa60","cbe43e2bad5ac903"]]},{"id":"cbe43e2bad5ac903","type":"http request","z":"e0263d19a83676e6","name":"","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":true,"proxy":"","insecureHTTPParser":true,"authType":"","senderr":false,"headers":[],"x":430,"y":260,"wires":[["99d1772b779dadb3","5c34bea42383719b","f399d38a516ba036","3f2b1873c9858ffa","e50259c33c62cae4"]]},{"id":"c3cd1b0b6dd5cb7d","type":"debug","z":"e0263d19a83676e6","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"headers","targetType":"msg","statusVal":"","statusType":"auto","x":410,"y":120,"wires":[]},{"id":"cecedc157612aa60","type":"debug","z":"e0263d19a83676e6","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":390,"y":160,"wires":[]},{"id":"5c34bea42383719b","type":"debug","z":"e0263d19a83676e6","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"responseCookies","targetType":"msg","statusVal":"","statusType":"auto","x":660,"y":60,"wires":[]},{"id":"f399d38a516ba036","type":"debug","z":"e0263d19a83676e6","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"statusCode","targetType":"msg","statusVal":"","statusType":"auto","x":640,"y":140,"wires":[]},{"id":"3f2b1873c9858ffa","type":"debug","z":"e0263d19a83676e6","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"headers","targetType":"msg","statusVal":"","statusType":"auto","x":630,"y":180,"wires":[]},{"id":"e50259c33c62cae4","type":"function","z":"e0263d19a83676e6","name":"GET","func":"var cookies = msg.responseCookies;\nvar payload = msg.payload;\nmsg.headers={};\nmsg.cookies = cookies;\nmsg.method = \"GET\"\nmsg.url = \"https://owd5-r1099-app.ojelectronics.com/api/Group/GroupContents?sessionid=\" + payload.SessionId + \"&APIKEY=f219aab4-9ac0-4343-8422-b72203e2fac9\";\n//msg.url = \"https://owd5-mh015-app.ojelectronics.com/api/UserProfile/SignIn\";\nmsg.headers[\"Accept\"] = \"application/json; charset=utf-8\"\n//msg.headers[\"Content-Type\"] = \"application/json; charset=utf-8\"\n//msg.headers[\"Content-Type\"] = \"application/json\"\n//msg.headers[\"Content-Type\"] = \"application/x-www-form-urlencoded\"\n//msg.headers[\"User-Agent\"] = \"Dalvik/2.1.1 (Linux; U; Android 6.0.1; LG-H955 Build/MMB29M)\"\n//msg.headers[\"Host\"] = \"owd5-r1099-app.ojelectronics.com\"\n//msg.headers[\"connection\"] = \"Keep-Alive\"\n//msg.headers[\"Accept-Encoding\"] = \"gzip\"\n//msg.headers[\"Content-Length\"] = \"147\"\nmsg.headers[\"Cookie\"] = msg.cookies\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":630,"y":260,"wires":[["80806d9fdd13b4e5","2a1f2eee8ec13822","215a0cff42e95e93","bb34643926129db1"]]},{"id":"80806d9fdd13b4e5","type":"debug","z":"e0263d19a83676e6","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"cookies","targetType":"msg","statusVal":"","statusType":"auto","x":910,"y":100,"wires":[]},{"id":"543459c338fdf022","type":"comment","z":"e0263d19a83676e6","name":"Thermostat test","info":"","x":120,"y":60,"wires":[]},{"id":"2a1f2eee8ec13822","type":"debug","z":"e0263d19a83676e6","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"headers","targetType":"msg","statusVal":"","statusType":"auto","x":910,"y":140,"wires":[]},{"id":"215a0cff42e95e93","type":"http request","z":"e0263d19a83676e6","name":"","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":true,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":850,"y":260,"wires":[["d761323c71e31933","307c384836989811","5fbd744d568d3a65"]]},{"id":"d761323c71e31933","type":"debug","z":"e0263d19a83676e6","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1110,"y":120,"wires":[]},{"id":"307c384836989811","type":"debug","z":"e0263d19a83676e6","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"headers","targetType":"msg","statusVal":"","statusType":"auto","x":1110,"y":160,"wires":[]},{"id":"bb34643926129db1","type":"debug","z":"e0263d19a83676e6","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"url","targetType":"msg","statusVal":"","statusType":"auto","x":900,"y":180,"wires":[]},{"id":"85528b133b3417b8","type":"mqtt out","z":"e0263d19a83676e6","name":"","topic":"","qos":"1","retain":"true","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"08297b6e8c8c1fdf","x":550,"y":380,"wires":[]},{"id":"b85d847f397e9d02","type":"change","z":"e0263d19a83676e6","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.GroupContents[0].Thermostats[2].ThermostatName","tot":"msg"},{"t":"set","p":"topic","pt":"msg","to":"Thermostats/Room_Z/ThermostatName","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":380,"y":600,"wires":[["2d86bde923a21172"]]},{"id":"2d86bde923a21172","type":"mqtt out","z":"e0263d19a83676e6","name":"","topic":"","qos":"1","retain":"true","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"08297b6e8c8c1fdf","x":550,"y":600,"wires":[]},{"id":"71d80512bf128717","type":"mqtt out","z":"e0263d19a83676e6","name":"","topic":"","qos":"1","retain":"true","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"08297b6e8c8c1fdf","x":550,"y":420,"wires":[]},{"id":"c6fe90d025c50587","type":"mqtt out","z":"e0263d19a83676e6","name":"","topic":"","qos":"1","retain":"true","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"08297b6e8c8c1fdf","x":550,"y":460,"wires":[]},{"id":"e3a737fc5eb4a98e","type":"mqtt out","z":"e0263d19a83676e6","name":"","topic":"","qos":"1","retain":"true","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"08297b6e8c8c1fdf","x":550,"y":500,"wires":[]},{"id":"50adb823903fb0a0","type":"mqtt out","z":"e0263d19a83676e6","name":"","topic":"","qos":"1","retain":"true","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"08297b6e8c8c1fdf","x":550,"y":540,"wires":[]},{"id":"1ac9c16c7e9d831f","type":"comment","z":"e0263d19a83676e6","name":"Thermostat Room_A","info":"","x":370,"y":320,"wires":[]},{"id":"5fbd744d568d3a65","type":"junction","z":"e0263d19a83676e6","x":60,"y":320,"wires":[["83d6de01d96ec96e","ea69aba7bc52427f","bf0d23c19014e679","b85d847f397e9d02","a758cc700caa388f","30d20d6ff7811a53"]]},{"id":"7f45fcb61c725a82","type":"group","z":"e0263d19a83676e6","style":{"stroke":"#999999","stroke-opacity":"1","fill":"none","fill-opacity":"1","label":true,"label-position":"nw","color":"#a4a4a4"},"nodes":["83d6de01d96ec96e","a758cc700caa388f","ea69aba7bc52427f","30d20d6ff7811a53","bf0d23c19014e679"],"x":274,"y":339,"w":212,"h":242},{"id":"83d6de01d96ec96e","type":"change","z":"e0263d19a83676e6","g":"7f45fcb61c725a82","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.GroupContents[0].Thermostats[3].ThermostatName","tot":"msg"},{"t":"set","p":"topic","pt":"msg","to":"Thermostats/Room_A/ThermostatName","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":380,"y":380,"wires":[["85528b133b3417b8"]]},{"id":"a758cc700caa388f","type":"change","z":"e0263d19a83676e6","g":"7f45fcb61c725a82","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.GroupContents[0].Thermostats[3].RoomTemperature/100","tot":"jsonata"},{"t":"set","p":"topic","pt":"msg","to":"Thermostats/Room_A/RoomTemperature","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":380,"y":420,"wires":[["71d80512bf128717"]]},{"id":"ea69aba7bc52427f","type":"change","z":"e0263d19a83676e6","g":"7f45fcb61c725a82","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.GroupContents[0].Thermostats[3].FloorTemperature/100","tot":"jsonata"},{"t":"set","p":"topic","pt":"msg","to":"Thermostats/Room_A/FloorTemperature","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":380,"y":460,"wires":[["c6fe90d025c50587"]]},{"id":"30d20d6ff7811a53","type":"change","z":"e0263d19a83676e6","g":"7f45fcb61c725a82","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.GroupContents[0].Thermostats[3].Heating","tot":"msg"},{"t":"set","p":"topic","pt":"msg","to":"Thermostats/Room_A/Heating","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":380,"y":500,"wires":[["e3a737fc5eb4a98e"]]},{"id":"bf0d23c19014e679","type":"change","z":"e0263d19a83676e6","g":"7f45fcb61c725a82","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.GroupContents[0].Thermostats[3].ManualModeSetpoint/100","tot":"jsonata"},{"t":"set","p":"topic","pt":"msg","to":"Thermostats/Room_A/ManualModeSetpoint","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":380,"y":540,"wires":[["50adb823903fb0a0"]]},{"id":"08297b6e8c8c1fdf","type":"mqtt-broker","name":"","broker":"192.168.2.10","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":{},"sessionExpiry":"","credentials":{}}]

and entities in HA :smiley:

I’ll be testing manual temperature set. Basically my goal is to do automation and start heating once there’s energy surplus from my solar system.

Test it and let me know your results.

1 Like

Hi guys. I also just bought the MWD5. Fiddling around in node-red with your flow, and looking promising :slight_smile:
Small question: how do you find you API key?

Btw, I have the full decompiled source code for the android app if that might be interesting?

@dlysnes I just used the API key that I sniffed from the app, so it is really the app-creators API key.
I’m afraid I cant do much with the source code of the app, but I do think I have what I need in node red now.
I’ve set it up so that it creates devices in Home Assistant for the thermostats, via MQTT.
The following entities are available in the device:

  1. climate entity with the ability to set manual temperature or select a presets from the app (vacation, comfort, boost)
  2. Power and energy consumption sensors (Connected “Load” needs to be manually input in home assistant device page)
  3. Floor and Room temperatures, as well as a sensor for “Main Temperature sensor” which is either “Floor” or “Room”

I’ve only got one MWD5 thermostat, so I can’t guarantee that it works with many, but I have created it with that in mind, so I hope @zdenek.masek could test that for me.

I’m completely new to NodeRed, so I have taken some shortcuts with function nodes with a lot of code in them istead of using more nodes to better visualize the automation.

How it works:
The flow launches the login procedure at startup and every hour.
It updates the thermostats from the server every minute and stores everything in flow context.
It then updates Home Assistant by publishing data to the MQTT broker.
Every hour it runs a code for creating mqtt config for every thermostat, this is just for when you add a new thermostat, so it could be a manual procedure.
When you change values on a thermostat in Home Assistant it publishes these to MQTT broker and NodeRed posts the changes to the server, and stores settings like “Connected Load” in flow context.
It also publishes the change automatically to Home Assistant just to prevent odd behaviour (like if you change temperature from 20 to 22, and it changes back to 20 after a couple of seconds, and then when it updates from the server it changes to 22 again)
The energy consumption is a little bit strange. In the app you always get yesterdays energy consumption as the last available, but I found out that if I provide tomorrows date in the POST request I get todays energy consumption, which updates every hour.
When in Schedule-preset, there were no “set-temperature” available in the data from the server, so I get that from the schedule data, by checking todays program (backwards) for an active program with a timestamp lower than current time, and if it does not find one it gets the last active program from yesterday.

If someone could test it out It would be great, since I am trying to learn from my mistakes here :slight_smile:


Processing: mwd5.json…

1 Like
[{"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"}]

This is extremely exiting stuff, the MWD5 has been a missing link in my home energy monitoring!

Just installed your Nodered flow and it´s /kinda/ working for me.

Looks like I am having some problem with publishing to MQTT.
When looking at the data out from “Extract mqtt data and topic” I see both config and state topics (including good data from MWD5 in state) but when checking MQTT broker with MQTT explorer, I can only see the config topics.
Any tips on how to carry on faultfinding? (Please bear with me, I´m new to this)
Attaching node 7 output (which looks fine)

And here is what I am seeing in MQTT Explorer; no state topic

I can only post 3 replies in this topic, so I need to edit.
MQTT started working when I made an input node subscribing to one of the topics, strangely.

The flow works fine for me when MWD5 is in manual mode.
When in program mode I get errors, as you can see in the pic below.

My man!
Imported the flow, did a couple of small adjustments (user / pass / mqtt) and it works perfect. I really must say this is one of the coolest setups so far in HA - NR. I will continue testing it, and also add powersaver and other flows to control it. Thanx a lot!

/D

I’m sorry for not answering here sooner, been quite busy, and forgot all about it.
I found a mistake in the code, I was using hardcoded serial for my thermostat in the function.

Double click the “Prepare MQTT Values” block and change the following lines:

14: function getScheduleTemp(serial) {
33: var schedule = flow.get(`Thermostats.${serial}.Schedule.Days.${day}.Events`)
46: schedule = flow.get(`Thermostats.${serial}.Schedule.Days.${yesterday}.Events`)
79: if (t.RegulationMode == 1) temperature = getScheduleTemp(serial)

You can also remove all lines containing “chosen” as that was something I used when debugging.

I’ve also added an events node with “homeassistant_start” event to several nodes to make sure everything comes back up after reboot etc.

Looks very good now after editing the last 4 lines, thank you so much for your time and effort.

Now, for me the next is finding out how to get the energy consumption accumulated so I can use it for utility meters and getting a weekly, monthly and annual consumption graph.

I was actually surprised to see how much of our house consumption is used for bathroom floor heating.

And to my surprise, the Utility meter does this just fine even when the sensor returns to Zero every night.
Again, thank you @oppigard for putting down the time and effort, and then sharing with the community.

Thanks for the node-red flow! Super useful :slight_smile:

I found two issues:

  • My energy dashboard was showing energy as negative after every update at 12:58. I’ve changed the state_class to “total_increasing” in an attempt to mitigate this. I believe that this is the correct thing to do based on the documentation. After a few days of watching, this seems to be working correctly.

  • I’m getting Payload '{"load":0}' is not a Number frequently in my HA logs. I believe the culprit is line #128 in Prepare MQTT Values which maybe should be assigning power?

Super Nice flow.

I tried to snif the api key, but cannot find it. Tried several android apps, wireshark, windows subsystem for android, but without any luck.

Can anyone give me an advise which app or program I can use best to get myself the API key.

Thanks in advance!

Thank you for the input!
I’m also getting the '{"load": 0}' thing, but it seems to fix itself after a while. Also I have a problem with the “installed_power” resetting when I restarted HAOS with NodeRED, but I am in the processing of moving to HA Core with separate NodeRED so I will hopefully have more time to check up on these things in the near future.

Why can’t you use the API-key that I provided in the first post?
Since they don’t have an open API, we need to “borrow” the API key of the app, and that would not be unique for every installation (at leaast I don’t think so).

1 Like