Ubisys H1 Smart Radiator Thermostat

https://www.ubisys.de/produkte/produkte-klima/heizungssteuerung-h1

Interesting seems to be new?
We’ll try to get one sample from Ubisys

ubisys H1 Firmware Änderungsprotokoll – ubisys first update from 12. Mai 2022

Maybe not that new. I always wanted to try it out and now they hat a discount, so I bought it.

Control via deCONZ already works. But I have no success adding or reading schedules which was added in the last firmware:

  • Schedules now manageable over-the-air using standard ZCL commands

From a quick look we don’t have a DDF for the H1 yet. I guess we will add the basic functionality first so it shows up in the REST API and Phoscon App, the schedules functionality is usually a bit more involved but should be doable.

1 Like

schedules can be done on the device, so thats not really urgent. Being able to control Occupied Heating Setpoint and System Mode (Heat, Off) and read PI Heating Demand (valve position) would be nice. (And whatever is needed to get it into homebridge-deconz)

I tried to “write” my own DDF. I took the Bosch Thermostat II DDF and stipped it down.

But just nothing happend :frowning:

Change the status to gold

1 Like

Nice!

curl -vv -XPUT .../sensors/122/config --data '{"heatsetpoint": 2100}'

works.

{
  "config": {
    "battery": 95,
    "heatsetpoint": 2000,
    "mode": "heat",
    "offset": 0,
    "on": true,
    "reachable": true
  },
  "ep": 1,
  "etag": "3aa993ad8b1d6c520d8eb0cf74a9e74c",
  "lastannounced": null,
  "lastseen": "2023-12-04T12:50Z",
  "manufacturername": "ubisys",
  "modelid": "H1",
  "name": "Thermostat",
  "state": {
    "errorcode": null,
    "lastupdated": "2023-12-04T12:50:39.990",
    "on": null,
    "temperature": 1800,
    "valve": 29
  },
  "swversion": "1.4.0",
  "type": "ZHAThermostat",
  "uniqueid": "00:1f:ee:00:00:00:98:73-01-0201"
}

and it appears in Phoscon and works there, too :partying_face:

I guess it’s not all correct here (afaik it does not have an AUTO mode) but it works for now:

Edit: and it just works in homebridge-deconz, too

{
  "schema": "devcap1.schema.json",
  "manufacturername": "Ubisys",
  "modelid": "H1",
  "vendor": "Ubisys",
  "product": "H1",
  "sleeper": false,
  "status": "Gold",
  "path": "/devices/ubisys/h1.json",
  "subdevices": [
    {
      "type": "$TYPE_THERMOSTAT",
      "restapi": "/sensors",
      "uuid": [
        "$address.ext",
        "0x01",
        "0x0201"
      ],
      "meta": {
        "values": {
          "config/mode": {
            "auto": 0,
            "heat": 1,
            "off": 5
          }
        }
      },
      "fingerprint": {
        "profile": "0x0104",
        "device": "0x0301",
        "endpoint": "0x01",
        "in": [
          "0x0001",
          "0x0201",
          "0x0204",
          "0x0B05"
        ]
      },
      "items": [
        {
          "name": "attr/id"
        },
        {
          "name": "attr/lastannounced"
        },
        {
          "name": "attr/lastseen"
        },
        {
          "name": "attr/manufacturername"
        },
        {
          "name": "attr/modelid"
        },
        {
          "name": "attr/name"
        },
        {
          "name": "attr/swversion"
        },
        {
          "name": "attr/type"
        },
        {
          "name": "attr/uniqueid"
        },
        {
          "name": "config/battery",
          "refresh.interval": 43265,
          "read": {
            "at": "0x0021",
            "cl": "0x0001",
            "ep": 1,
            "fn": "zcl"
          },
          "parse": {
            "at": "0x0021",
            "cl": "0x0001",
            "ep": 1,
            "eval": "Item.val = Attr.val / 2;",
            "fn": "zcl:attr"
          },
          "default": 0
        },
        {
          "name": "config/heatsetpoint",
          "refresh.interval": 360,
          "read": {
            "at": "0x0012",
            "cl": "0x0201",
            "ep": 1,
            "fn": "zcl"
          },
          "default": 0
        },
        {
          "name": "config/mode",
          "refresh.interval": 3600,
          "read": {
            "at": "0x4007",
            "cl": "0x0201",
            "ep": 1,
            "fn": "zcl:attr",
            "mf": "0x1209"
          },
          "write": {
            "at": "0x4007",
            "cl": "0x0201",
            "dt": "0x30",
            "ep": 1,
            "eval": "if (Item.val == 'auto') { 0 } else if (Item.val == 'heat') { 1 } else if (Item.val == 'off') { 5 };",
            "fn": "zcl:attr",
            "mf": "0x1209"
          },
          "parse": {
            "at": "0x4007",
            "cl": "0x0201",
            "ep": 1,
            "eval": "if (Attr.val == 0) { Item.val = 'auto' } else if (Attr.val == 1) { Item.val = 'heat' } else if (Attr.val == 5) { Item.val = 'off' };",
            "fn": "zcl:attr",
            "mf": "0x1209"
          },
          "default": "heat"
        },
        {
          "name": "config/on"
        },
        {
          "name": "config/reachable"
        },
        {
          "name": "state/lastupdated"
        },
        {
          "name": "state/temperature",
          "refresh.interval": 360,
          "read": {
            "at": "0x0000",
            "cl": "0x0201",
            "ep": 1,
            "fn": "zcl"
          },
          "parse": {
            "at": "0x0000",
            "cl": "0x0201",
            "ep": 1,
            "eval": "Item.val = Attr.val;",
            "fn": "zcl:attr"
          },
          "default": 0
        },
        {
          "name": "state/valve",
          "read": {
            "at": "0x0008",
            "cl": "0x0201",
            "ep": 1,
            "fn": "zcl"
          },
          "default": 0
        }
      ]
    }
  ],
  "bindings": [
    {
      "bind": "unicast",
      "src.ep": 1,
      "cl": "0x0001",
      "report": [
        {
          "at": "0x0021",
          "dt": "0x20",
          "min": 3600,
          "max": 43200,
          "change": "0x00000002"
        }
      ]
    },
    {
      "bind": "unicast",
      "src.ep": 1,
      "cl": "0x0201",
      "report": [
        {
          "at": "0x0000",
          "dt": "0x29",
          "min": 60,
          "max": 300,
          "change": "0x00000032"
        },
        {
          "at": "0x0012",
          "dt": "0x29",
          "min": 1,
          "max": 300,
          "change": "0x00000001"
        },
        {
          "at": "0x0008",
          "dt": "0x30",
          "mf": "0x1209",
          "min": 1,
          "max": 300,
          "change": "0x00000001"
        }
      ]
    }
  ]
}
2 Likes

Getting mine Tue or Wed. Exited to reveal any additional secrets :smiley:

1 Like

I think somehow I configuried it so it updates way too much, there it at least one update per second:

time                           age_secs battery id  name                    source    temperature type          valve
----                           -------- ------- --  ----                    ------    ----------- ----          -----
2023-12-05T06:02:35.345306233Z 0        95      122 Thermostat 				websocket 17.5        ZHAThermostat 100
2023-12-05T06:01:22.625593248Z 0        95      122 Thermostat				websocket 17.5        ZHAThermostat 100
2023-12-05T06:01:00.037504508Z 0        95      122 Thermostat				websocket 17.5        ZHAThermostat 100
2023-12-05T06:00:06.875159308Z 0        95      122 Thermostat 				websocket 17.5        ZHAThermostat 100
2023-12-05T05:59:47.475149668Z 0        95      122 Thermostat 				websocket 17.5        ZHAThermostat 100
2023-12-05T05:59:05.805337856Z 0        95      122 Thermostat 				websocket 17.5        ZHAThermostat 100
2023-12-05T05:58:53.737278808Z 0        95      122 Thermostat 				websocket 17.5        ZHAThermostat 100
2023-12-05T05:58:31.124283762Z 0        95      122 Thermostat 				websocket 17.5        ZHAThermostat 100
2023-12-05T05:57:38.41547285Z  0        95      122 Thermostat 				websocket 17.5        ZHAThermostat 100
2023-12-05T05:57:15.305127917Z 0        95      122 Thermostat 				websocket 17.5        ZHAThermostat 100
2023-12-05T05:56:22.626316369Z 0        95      122 Thermostat 				websocket 17.5        ZHAThermostat 100
2023-12-05T05:56:00.121421302Z 0        95      122 Thermostat 				websocket 17.5        ZHAThermostat 100
2023-12-05T05:55:06.865590587Z 0        95      122 Thermostat 				websocket 17.5        ZHAThermostat 100
2023-12-05T05:54:47.455520795Z 0        95      122 Thermostat 				websocket 17.5        ZHAThermostat 100
2023-12-05T05:54:05.805767784Z 0        95      122 Thermostat 				websocket 17.5        ZHAThermostat 100
2023-12-05T05:53:52.239981776Z 0        95      122 Thermostat 				websocket 17.5        ZHAThermostat 100
2023-12-05T05:53:30.13480626Z  0        95      122 Thermostat 				websocket 17.5        ZHAThermostat 100
2023-12-05T05:52:37.497406203Z 0        95      122 Thermostat 				websocket 17.5        ZHAThermostat 100
2023-12-05T05:52:15.325060835Z 0        95      122 Thermostat 				websocket 17.5        ZHAThermostat 100
2023-12-05T05:51:17.635524616Z 0        95      122 Thermostat 				websocket 17.5        ZHAThermostat 100

Try giving state/valve a refresh interval. You can remove everything but the name for the item, read and parse functions are defined in the generic item.

> select * from deflux_ZHAThermostat order by time desc limit 20;
name: deflux_ZHAThermostat
time                           age_secs battery heatsetpoint id  name		source    temperature type          valve
----                           -------- ------- ------------ --  ----		------    ----------- ----          -----
2023-12-06T10:05:28.191035304Z 0        95      18           122 Thermostat	websocket 18.5        ZHAThermostat 0
2023-12-06T10:05:22.170726371Z 0        95      18           122 Thermostat	websocket 18.5        ZHAThermostat 0
2023-12-06T10:05:11.082516097Z 0        95      18           122 Thermostat	websocket 18.5        ZHAThermostat 0
2023-12-06T10:03:50.261510361Z 0        95      18           122 Thermostat	websocket 18.5        ZHAThermostat 0
2023-12-06T10:02:34.955220841Z 0        95      18           122 Thermostat websocket 18.5        ZHAThermostat 0
2023-12-06T10:02:28.400470557Z 0        95      18           122 Thermostat websocket 18.5        ZHAThermostat 0
2023-12-06T10:01:16.433794251Z 0        95      18           122 Thermostat websocket 18.5        ZHAThermostat 0
2023-12-06T10:00:02.071391546Z 0        95      18           122 Thermostat websocket 18.5        ZHAThermostat 0
2023-12-06T09:58:57.305365354Z 0        95      18           122 Thermostat websocket 18.5        ZHAThermostat 0
2023-12-06T09:58:45.760960133Z 0        95      18           122 Thermostat websocket 18.5        ZHAThermostat 0
2023-12-06T09:57:29.920882017Z 0        95      18           122 Thermostat websocket 18.5        ZHAThermostat 0
2023-12-06T09:57:28.400966903Z 0        95      18           122 Thermostat websocket 18.5        ZHAThermostat 0
2023-12-06T09:56:21.422256194Z 0        95      18           122 Thermostat websocket 18.5        ZHAThermostat 0
2023-12-06T09:54:58.990939438Z 0        95      18           122 Thermostat websocket 18.5        ZHAThermostat 0
2023-12-06T09:53:44.703732191Z 0        95      18           122 Thermostat websocket 18.5        ZHAThermostat 0
2023-12-06T09:52:28.931215671Z 0        95      18           122 Thermostat websocket 18.5        ZHAThermostat 0
2023-12-06T09:52:28.411056156Z 0        95      18           122 Thermostat websocket 18.5        ZHAThermostat 0
2023-12-06T09:52:21.621171132Z 0        95      18           122 Thermostat websocket 18.5        ZHAThermostat 0
2023-12-06T09:51:11.3268279Z   0        95      18           122 Thermostat websocket 18.5        ZHAThermostat 0
2023-12-06T09:49:50.001297446Z 0        95      18           122 Thermostat websocket 18.5        ZHAThermostat 0
{
  "schema": "devcap1.schema.json",
  "manufacturername": "Ubisys",
  "modelid": "H1",
  "vendor": "Ubisys",
  "product": "H1",
  "sleeper": false,
  "status": "Gold",
  "path": "/devices/ubisys/h1.json",
  "subdevices": [
    {
      "type": "$TYPE_THERMOSTAT",
      "restapi": "/sensors",
      "uuid": [
        "$address.ext",
        "0x01",
        "0x0201"
      ],
      "meta": {
        "values": {
          "config/mode": {
            "auto": 0,
            "heat": 1,
            "off": 5
          }
        }
      },
      "fingerprint": {
        "profile": "0x0104",
        "device": "0x0301",
        "endpoint": "0x01",
        "in": [
          "0x0001",
          "0x0201",
          "0x0204",
          "0x0B05"
        ]
      },
      "items": [
        {
          "name": "attr/id"
        },
        {
          "name": "attr/lastannounced"
        },
        {
          "name": "attr/lastseen"
        },
        {
          "name": "attr/manufacturername"
        },
        {
          "name": "attr/modelid"
        },
        {
          "name": "attr/name"
        },
        {
          "name": "attr/swversion"
        },
        {
          "name": "attr/type"
        },
        {
          "name": "attr/uniqueid"
        },
        {
          "name": "config/battery",
          "refresh.interval": 43265,
          "read": {
            "at": "0x0021",
            "cl": "0x0001",
            "ep": 1,
            "fn": "zcl:attr"
          },
          "parse": {
            "at": "0x0021",
            "cl": "0x0001",
            "ep": 1,
            "eval": "Item.val = Attr.val / 2;",
            "fn": "zcl:attr"
          },
          "default": 0
        },
        {
          "name": "config/heatsetpoint",
          "refresh.interval": 360,
          "read": {
            "at": "0x0012",
            "cl": "0x0201",
            "ep": 1,
            "fn": "zcl"
          },
          "default": 0
        },
        {
          "name": "config/mode",
          "refresh.interval": 3600,
          "read": {
            "at": "0x4007",
            "cl": "0x0201",
            "ep": 1,
            "fn": "zcl:attr",
            "mf": "0x1209"
          },
          "write": {
            "at": "0x4007",
            "cl": "0x0201",
            "dt": "0x30",
            "ep": 1,
            "eval": "if (Item.val == 'auto') { 0 } else if (Item.val == 'heat') { 1 } else if (Item.val == 'off') { 5 };",
            "fn": "zcl:attr",
            "mf": "0x1209"
          },
          "parse": {
            "at": "0x4007",
            "cl": "0x0201",
            "ep": 1,
            "eval": "if (Attr.val == 0) { Item.val = 'auto' } else if (Attr.val == 1) { Item.val = 'heat' } else if (Attr.val == 5) { Item.val = 'off' };",
            "fn": "zcl:attr",
            "mf": "0x1209"
          },
          "default": "heat"
        },
        {
          "name": "config/on"
        },
        {
          "name": "config/reachable"
        },
        {
          "name": "state/lastupdated"
        },
        {
          "name": "state/temperature",
          "refresh.interval": 360,
          "read": {
            "at": "0x0000",
            "cl": "0x0201",
            "ep": 1,
            "fn": "zcl"
          },
          "parse": {
            "at": "0x0000",
            "cl": "0x0201",
            "ep": 1,
            "eval": "Item.val = Attr.val;",
            "fn": "zcl:attr"
          },
          "default": 0
        },
        {
          "name": "state/valve",
          "refresh.interval": 360,
          "read": {
            "at": "0x0008",
            "cl": "0x0201",
            "ep": 1,
            "fn": "zcl"
          },
          "default": 0
        },
        {
          "name": "state/voltage",
          "refresh.interval": 300,
          "parse": {
            "at": "0x0020",
            "cl": "0x0001",
            "ep": 1,
            "eval": "if (Attr.val != 65535) { Item.val = Attr.val; }"
          },
          "default": 0
        }
      ]
    }
  ],
  "bindings": [
    {
      "bind": "unicast",
      "src.ep": 1,
      "cl": "0x0001",
      "report": [
        {
          "at": "0x0021",
          "dt": "0x20",
          "min": 3600,
          "max": 43200,
          "change": "0x00000002"
        },
        {
          "at": "0x0020",
          "dt": "0x20",
          "min": 3600,
          "max": 43200,
          "change": "0x00000001"
        }
      ]
    },
    {
      "bind": "unicast",
      "src.ep": 1,
      "cl": "0x0201",
      "report": [
        {
          "at": "0x0000",
          "dt": "0x29",
          "min": 60,
          "max": 300,
          "change": "0x00000032"
        },
        {
          "at": "0x0012",
          "dt": "0x29",
          "min": 60,
          "max": 300,
          "change": "0x00000032"
        },
        {
          "at": "0x0008",
          "dt": "0x30",
          "mf": "0x1209",
          "min": 60,
          "max": 300,
          "change": "0x00000001"
        }
      ]
    }
  ]
}

Ah, config/mode is also incorrect and from a different device? Ubisys has a different manufacturer code.

I could not figure out how to start from scratch so I used the Bosch Thermostat II DDF and changed things. I did not change the mode, yes.

I guess it’s not all correct here (afaik it does not have an AUTO mode) but it works for now