Having Hozelock cloud controller kit intergration

I was wondering if and wen Hozelock Will be a supported censor. I have a cloud controller kit and would like to intergratie this. Maybe anyone any tips.

How are you doing with this? I have also just ordered one and am also wanting to integrate into HA.

I automated my Hozelock Cloud Controller with shell scripts which call the (undocumented) cloud API (reverse-engineered from looking at requests made by the android app), I didn’t look at local (ie no cloud dependency) control.

The device has pretty much 0 security, requests to the API have no authentication, and just identify each device by its unique device ID. I raised this issue with Hozelock, and proved it to them by remotely activating a device in their office, but they weren’t at all interested. (never followed up or made any changes to it)

There’s a basic bash script below for turning the controller on/off, the API endpy to start/stop is waterNow/stopWatering. iirc you should be able to play with the API to find all available endpoints

For status & feedback you can make a GET request to
http://hoz3.com/restful/support/hubs/HUBID/, which returns status as JSON.


ACTION=$1
DURATION=$2

PAYLOAD='{"controllerIDs":["0","0"],"duration":'${DURATION}'}'

curl -X POST "http://hoz3.com/restful/foo/hubs/${HUBID}/controllers/actions/${ACTION}" -H 'content-type: application/json' -d $PAYLOAD > /dev/null 2>&1```
2 Likes

Good Stuff.

Shame it is so open, you would almost want to network isolate that hub and just address and control it locally form HA. Thanks for that data, will see how it works when it finally gets delivered.

On a side note, when would you like me to water your garden?

Assuming that all of the 6 character hub ID’s follow the LNLLNL format, then there are only 45,697,600 possible ID’s.

There’s also no API rate-limiting on their server, so polling it (annoyingly with a GET as it doesn’t respond to HEAD requests) to see which ID’s respond would give you a complete list of all live hubs.

There I was wanting to just water our gardens, but you want to water the world! How benevolent.

Not a home-assist user my self, however my hubs number/Letter format is LNNNLN.

There may be up to 10,314,424,798,490,500,000,000,000,000 combinations on the basis of 6^36, of course in reality a lot of combinations won’t exist such as all numbers or those less than 6 digits.

Regards: eveares.

Thanks to @anthonyangel I wrote up everything I learnt about the Hozelock API and included more information form what he shared.

I was going to post it here but it got … long.

Hope it is helpful to some of you.

3 Likes

Thanks - interesting read.
Personally I think it’s absolutely shocking that there is no forced TLS or any auth at all on their API.
Especially since @anthonyangel took the time to demonstrate that he could control their device.
Its extremely irresponsible.

Has anyone found out how the traffic is between the hub and the server? Is it possible to create your own server?

Cheers

Here’s a config code for sensors. I recon it could be done better using binary_sensor for some of the variables.
Im still working on sending commands to the controller.

[updated version - 29.07.2019]

sensors:
  - platform: rest
    resource: !secret hozelock_controller_0
    name: "Hozelock Back Garden Sprinkler"
    value_template: '{{ value_json["controller"]["name"] }}'
    json_attributes:
      - controller
- platform: template
    sensors:
      hozelock_back_garden_sprinkler_pause_starttime:
        friendly_name: "Pause start"
        value_template: '{{ ( state_attr("sensor.hozelock_back_garden_sprinkler", "controller")["pause"]["startTime"] | int / 1000 ) | int | timestamp_local }}' 
      hozelock_back_garden_sprinkler_pause_endtime:
        friendly_name: "Pause end"
        value_template: '{{ ( state_attr("sensor.hozelock_back_garden_sprinkler", "controller")["pause"]["endTime"] | int / 1000 ) | int | timestamp_local }}'
      hozelock_back_garden_sprinkler_pause_duration:
        friendly_name: "Pause duration"
        value_template: '{{ ( state_attr("sensor.hozelock_back_garden_sprinkler", "controller")["pause"]["duration"] | int / 60000 ) | int }}'
      hozelock_back_garden_sprinkler_adjustment_starttime:
        friendly_name: "Adjustment start"
        value_template: '{{ ( state_attr("sensor.hozelock_back_garden_sprinkler", "controller")["adjustment"]["startTime"] | int / 1000 ) | int | timestamp_local }}'
      hozelock_back_garden_sprinkler_adjustment_endtime:
        friendly_name: "Adjustment end"
        value_template: '{{ ( state_attr("sensor.hozelock_back_garden_sprinkler", "controller")["adjustment"]["endTime"] | int / 1000 ) | int | timestamp_local }}'
      hozelock_back_garden_sprinkler_adjustment_wateringadjustment:
        friendly_name: "Adjustment amount"
        value_template: '{{ state_attr("sensor.hozelock_back_garden_sprinkler", "controller")["adjustment"]["wateringAdjustment"] }}'
        unit_of_measurement: '%'
      hozelock_back_garden_sprinkler_waternowevent:
        friendly_name: "Water now event"
        value_template: '{{ state_attr("sensor.hozelock_back_garden_sprinkler", "controller")["waterNowEvent"] }}'
      hozelock_back_garden_sprinkler_currentwateringevent:
        friendly_name: "Current watering event"
        value_template: '{{ state_attr("sensor.hozelock_back_garden_sprinkler", "controller")["currentWateringEvent"] }}'
      hozelock_back_garden_sprinkler_nextwateringevent_starttime:
        friendly_name: "Next watering start"
        value_template: '{{ ( state_attr("sensor.hozelock_back_garden_sprinkler", "controller")["nextWateringEvent"]["startTime"] | int / 1000 ) | int | timestamp_local }}'
      hozelock_back_garden_sprinkler_nextwateringevent_endtime:
        friendly_name: "Next watering end"
        value_template: '{{ ( state_attr("sensor.hozelock_back_garden_sprinkler", "controller")["nextWateringEvent"]["endTime"] | int / 1000 ) | int | timestamp_local }}'
      hozelock_back_garden_sprinkler_nextwateringevent_duration:
        friendly_name: "Next watering duration"
        value_template: '{{ ( state_attr("sensor.hozelock_back_garden_sprinkler", "controller")["nextWateringEvent"]["duration"] | int / 60000 ) | int}}'
        unit_of_measurement: 'min'
      hozelock_back_garden_sprinkler_lastcommunicationwithserver:
        friendly_name: "Last communication"
        value_template: '{{ ( state_attr("sensor.hozelock_back_garden_sprinkler", "controller")["lastCommunicationWithServer"] | int / 1000 ) | int | timestamp_local }}'
      hozelock_back_garden_sprinkler_nextcommunicationwithserver:
        friendly_name: "Next communication"
        value_template: '{{ ( state_attr("sensor.hozelock_back_garden_sprinkler", "controller")["nextCommunicationWithServer"] | int / 1000 ) | int | timestamp_local }}'
      hozelock_back_garden_sprinkler_batterystatus:
        friendly_name: "Battery status"
        value_template: '{{ state_attr("sensor.hozelock_back_garden_sprinkler", "controller")["batteryStatus"] }}'
      hozelock_back_garden_sprinkler_signalstrength:
        friendly_name: "Signal strength"
        value_template: '{{ state_attr("sensor.hozelock_back_garden_sprinkler", "controller")["signalStrength"] }}'
      hozelock_back_garden_sprinkler_overridescheduleduration:
        friendly_name: "Override schedule duration"
        value_template: '{{ state_attr("sensor.hozelock_back_garden_sprinkler", "controller")["overrideScheduleDuration"] }}'

binary_sensors:
- platform: template
    sensors:
      hozelock_back_garden_sprinkler_haswaternowevent:
        friendly_name: "Water now event"
        value_template: '{{ state_attr("sensor.hozelock_back_garden_sprinkler", "controller")["hasWaterNowEvent"] }}'
      hozelock_back_garden_sprinkler_ischildlockenabled:
        friendly_name: "Child lock"
        value_template: '{{ state_attr("sensor.hozelock_back_garden_sprinkler", "controller")["isChildlockEnabled"] }}'
      hozelock_back_garden_sprinkler_iswatering:
        friendly_name: "Watering now"
        value_template: '{{ state_attr("sensor.hozelock_back_garden_sprinkler", "controller")["isWatering"] }}'
      hozelock_back_garden_sprinkler_ispanelremoved:
        friendly_name: "Panel removed"
        value_template: '{{ state_attr("sensor.hozelock_back_garden_sprinkler", "controller")["isPanelRemoved"] }}'
      hozelock_back_garden_sprinkler_isadjusted:
        friendly_name: "Adjustment"
        value_template: '{{ state_attr("sensor.hozelock_back_garden_sprinkler", "controller")["isAdjusted"] }}'
      hozelock_back_garden_sprinkler_isscheduleuptodate:
        friendly_name: "Schedule up-to-date"
        value_template: '{{ state_attr("sensor.hozelock_back_garden_sprinkler", "controller")["isScheduleUpToDate"] }}'
      hozelock_back_garden_sprinkler_ispaused:
        friendly_name: "Paused"
        value_template: '{{ state_attr("sensor.hozelock_back_garden_sprinkler", "controller")["isPaused"] }}'
      hozelock_back_garden_sprinkler_nextwateringevent_enabled:
        friendly_name: "Next watering enabled"
        value_template: '{{ state_attr("sensor.hozelock_back_garden_sprinkler", "controller")["nextWateringEvent"]["enabled"] }}'

1 Like

And here’s a logic for rest_commands, please note, i havent tested all functions yet but they should work

rest_command: 
  hozelock_waternow:
    url: 'https://hoz3.com/restful/support/hubs/{{ hub_id }}/controllers/actions/waterNow'
    method: POST
    payload: '{"controllerIDs":[{{ controller_id }}],"duration":{{ duration }}}'
    content_type:  'application/json'

  hozelock_pause:
    url: 'https://hoz3.com/restful/support/hubs/{{ hub_id }}/controllers/actions/pause'
    method: POST
    payload: '{"controllerIDs":[{{ controller_id }}],"duration":{{ duration }}}'
    content_type:  'application/json'

  hozelock_unpause:
    url: 'https://hoz3.com/restful/support/hubs/{{ hub_id }}/controllers/actions/unpause'
    method: POST
    payload: '{"controllerIDs":[{{ controller_id }}]}'
    content_type:  'application/json'

  hozelock_adjust:
    url: 'https://hoz3.com/restful/support/hubs/{{ hub_id }}/controllers/actions/adjust'
    method: POST
    payload: '{"controllerIDs":[{{ controler_id }}],"duration":{{ duration }},"wateringAdjustment":{{ percentage }}}'
    content_type:  'application/json'

  hozelock_unadjust:
    url: 'https://hoz3.com/restful/support/hubs/{{ hub_id }}/controllers/actions/unadjust'
    method: POST
    payload: '{"controllerIDs":[{{ controller_id }}]}'
    content_type:  'application/json'

  hozelock_stopwatering:
    url: 'https://hoz3.com/restful/support/hubs/{{ hub_id }}/controllers/actions/stopWatering'
    method: POST
    payload: '{"controllerIDs":[{{ controller_id }}]}'
    content_type:  'application/json'

Hi @dinth
Can you explain how your code works because I tried it but everything is unknown (I can see the json values in my web browser when I go to http://hoz3.com/restful/support/hubs/xxxxxx)

@martynjsimpson
How can we use your API in home assistant?

There’s not much code above, just some sensor templates.
Are you getting any warnings in the log? Does the config validates in your HA?
Is the rest sensor unknown too?

I understand that everything depends on the rest sensor, but i get an unknown state. I’ve got no warnings in the log and the config validates in HA.

Do I need to change soething besides hozelock_controller_0 value ?
Can you explain value_template and json_attributes of the rest sensor ?

OK, got it: I was using http://hoz3.com/restful/support/hubs/xxxxxx for hozelock_conyroller_0 value but apparently we must use http://hoz3.com/restful/support/hubs/xxxxxx/controllers/0 instead. It was not obvious in your post :slightly_smiling_face:

Hi, could you make a clumsy guide?
I’m starting with the house assistant and it’s hard for me to follow the steps.
I would appreciate it very much and surely more people like me too.

hozelock_controller_0: https://hoz3.com/restful/support/hubs/XXXXX/controllers/0

replace XXXXX with your hub ID

Tell me if you want also to send commands, I will show you how I do it with the waternow command

thanks for answering.

I have copied Michal´s sensors code

  • platform: rest + platform: template sensors + binary_sensors

I have also copied everything in rest_command:

I have copied all this in configuration.yaml

then create secrets.yaml and copy the line

it is right ?

YOU should tell me if it’s right by clicking on Check config (left menu/Configuration/Server control) before restarting Home assistant and by testing :grinning:

If you want to use the commands hozelock_waternow, hozelock_stopwatering, hozelock_pause and hozelock_unpause, you must add:

  • in configuration.yaml:
input_number:
  hozelock_duration:
    name: Duration
    min: 1
    max: 60
    step: 1
    icon: mdi:clock-outline
    unit_of_measurement: "min"
  hozelock_duration_pause:
    name: Duration
    min: 1
    max: 14
    step: 1
    icon: mdi:clock-outline
    unit_of_measurement: "days"
  • in scripts.yaml:
hozelock_waternow:
  alias: Hozelock water now
  sequence:
    - service: rest_command.hozelock_waternow
      data_template:
        hub_id: !secret hozelock_hub_id
        controller_id: 0
        duration: "{{ states('input_number.hozelock_duration') | int * 60000 }}"
hozelock_stopwatering:
  alias: Hozelock stop watering
  sequence:
    - service: rest_command.hozelock_waternow
      data_template:
        hub_id: !secret hozelock_hub_id
        controller_id: 0
hozelock_pause:
  alias: Hozelock pause
  sequence:
    - service: rest_command.hozelock_pause
      data_template:
        hub_id: !secret hozelock_hub_id
        controller_id: 0
        duration: "{{ states('input_number.hozelock_duration_pause') }}"
hozelock_unpause:
  alias: Hozelock unpause
  sequence:
    - service: rest_command.hozelock_unpause
      data_template:
        hub_id: !secret hozelock_hub_id
        controller_id: 0
  • in secrets.yaml:
hozelock_hub_id: XXXXXX

replace XXXXXX with your hub id

I don’t use the others commands for now

Use the scripts to run the commands