Example: Energenie MiHome control and energy monitoring via REST API https://mihome4u.co.uk/

Please find below my working code for controlling and pulling data from the Energenie MiHome range of smart plugs / switches.

(For those unfamiliar with github you can use this link to download the latest folder: Download Link)


The templated switches are dynamically updated from the Energenie API, so they reflect the status of the switches even if you turn them off manually at the wall or via other means such as remote control or their website.

The measured wattage is retrieved and used as part of the energy monitoring capabilities of home assistant.

I’ve commented my code to try make it as self-explanatory as possible, but if you have any issues let me know.

Note: I personally use my own 433 MHz gateway for the Energenie wall light switches. However, their smart plugs use a two-way communication protocol, although still on 433 MHz it uses a different chipset and protocol, which I may look into doing a DIY solution in the future.
This would remove the reliance using the Energenie hardware gateway, a Internet connection and Energenie’s support for these products, both future proofing and enabling local control without Internet.

This is only been tested on:

  • Mi|Home Smart Plug+ Control and Monitor [MIHO005]
  • Mi|Home Smart Plug Monitor [MIHO004]
  • Mi|Home Gateway [MIHO001]

However, their API is pretty open and I do not see any reason why my code could not be expanded to cover their entire range of products including the thermostatic radiator valves (TRV’s) and other smart appliances.

Installation:

Copy the energenie_mihome folder and all of its contents into your Home Assistant’s packages folder This is often located inside of your /config folder. If you are running Hass.io , use SAMBA to copy the folder over. If you are running Home Assistant Supervised, the packages folder might be located at /usr/share/hassio/homeassistant. It is possible that your packages folder does not exist. If that is the case, create the folder in the proper location, and then copy the energenie_mihome folder and all of its contents inside the newly created packages folder.

Add the link to the Package to your configuration.yaml file, to the “homeassistant:” section. For me, I use:
packages: !include_dir_named packages/

image

Within my provided packages folder, I have one file per smart switch and a number file for the gateway.
Simply modify as follows:

  1. Identify the device ID you wish to control. The simplest way to do this is to login to the https://mihome4u.co.uk/devices and click “manage” on the device you wish to get the ID of. The web page that opens contains the ID at the last set of numbers in the URL.
    image.

  2. Optionally, get the ID of your gateway which is the first set of numbers in the URL.

  3. Within the folder, if you wish rename the file names to match the ID of the device wish to control, however this has no effect on anything.

  4. Either delete or edit the file energenie_mihome_gateway.yaml and add in your username password and the ID of your gateway.

  5. Open one of the switch files:
    a. Change !secret MiHome_ID and !secret MiHome_Password to your MiHome login details.
    b. Do a find and replace on the existing ID number, edit it to match your device number you wish to monitor and control.
    c. Rename the device friendly name to something you prefer, don’t forget spaces and case. E.G. “MiHome Ice Maker Switch” becomes “mihome_ice_maker_switch”.

  6. Finally add the Integration (Riemann sum integral) cumulative energy sensors to the energy dashboard.

That should be everything.

I’ve set the availability topic to monitor the state of the switch and if no voltage is detected after 240 seconds it’s marked as unavailable.
Therefore if you are using switches that are not bidirectional (I.E. only receive commands and do not respond) you need to comment out the “availability_template” line otherwise shall switches will always show as unavailable, or you could replace them with the status of the gateway although this won’t be specific for each switch just your entire environment as a whole.

UPDATE 2023:

I don’t trust Energenie to keep their servers online forever, so am designing my own self-hosted server to talk to the Energenie Products

See: GitHub - genestealer/node-red-energenie-ener314rt-home-assistant-mqtt: Node-Red Config for Energenie ener314rt with Home Assistant MQTT Auto Discovery

3 Likes

Hi Im trying to get my energine Gateway on to Home Assistant to contol my switches and I’m confused with the code energenie_mihome_gateway.yaml . I have the mac addressand ip address, but what is the defult port of the gateway? Is the label the name of the gateway, or is the user_id the gateway id? What is created_at, updated_at, auth_code, firmware_version_id, and last_seen_at ?

I am note a coder, so is it possible that you can you explan it a bit more in plain english?

Below is what I have managed to update here (XXXXXXXXXX) are included instead of my personal details.

sensor:
  - platform: rest # https://www.home-assistant.io/integrations/sensor.rest/
    name: "MiHome Gateway Status 1" # Could use a binary rest sensor, but then you could not have attributes.
    resource: 'https://mihome4u.co.uk/api/v1/devices/list'
    method: POST
    authentication: basic
    username: !secret XXXXXXXXXX
    password: !secret XXXXXXXXXX
    payload: '{}' # Leave blank
    # This sets the state as FALSE, if last_seen_at is more than 240 seconds ago.
    # value_template: '{{(now() - value_json.data.0.last_seen_at | as_datetime).seconds < 240}}' 
    value_template: "{{ as_timestamp(now()) - as_timestamp(value_json.data.0.last_seen_at) < 240 }}"
    json_attributes_path: "$.data.0"
    json_attributes:
      - mac_address XXXXXXXXXX
      - ip_address 192.168.1.132
      - port
      - label Home
      - user_id XXXXXXXXXX
      - created_at
      - updated_at
      - auth_code
      - firmware_version_id 1.5.9 12062018 
      - last_seen_at
    headers:
      Content-Type: application/json
    force_update: true
    scan_interval: 60

Kind regards

Tim

This is really great.
I got it up and running fairly quickly this morning on my HASS.io VM.
Two things.

  1. Would it be worth submitting this so it’s including in the main codebase because certainly works and fits.
  2. Is there any way to get Homeassistant to Identify the switches as proper unique entities, as they are, so I can assign them to the relevant rooms? The Identifiers calculated are based upon the homeassistant IDs which I’m pretty sure are unique and persistent…

Thanks,
David.

I have managed to also get it working fiddly.

I have created four new sensors from the entity attributes for today_wh and real_power.

#mihome sensors

    tumble_dryer:
          unique_id: "tumble_dryer"
          friendly_name: "tumble_dryer_today_wh"
          unit_of_measurement: "KWh"
          value_template: "{{ state_attr('sensor.tumble_dryer_status','today_wh') / 1000 }}"

    tumble_dryer_current:
          unique_id: "tumble_dryer_current"
          friendly_name: "tumble_dryer_current_kwh"
          unit_of_measurement: "KWh"
          value_template: "{{ state_attr('sensor.tumble_dryer_status','real_power') / 1000 }}"

This works but the today_wh appears not to reset every day. Any ideas?

Thanks

Also, the today_wh value is updated on the first day. But in the morning the value no longer updates or resets.

I have been trying to work this out myself too and found the following website to be very useful in learning the REST API from scratch. Its in one of @Richard.Huish 's configuration files. Give it a try:-

This website allows you to look at the API documentation on the MiHome website

https://mihome4u.co.uk/docs/api-documentation

from there you can figure out how to send commands to your own remote gateway, once you start to understand the concept of the API setting up the configuration files becomes a little easier.

UPDATE @Richard.Huish this is excellent, once I did a bit of self help and learned some of the REST API using the tool you very kindly linked in one of your configuration files (mentioned above^^) I have got this up and running, im able to turn my device off and on, monitor the power consumption and have the parameters of the gateway showing correctly.

Instruction 4 advises to add the ID of the gateway - this is not required and there’s no place for it to go into the energenie_mihome_gateway.yaml.

Instruction 5 - The yaml file already includes: -

username: !secret MiHome_ID
password: !secret MiHome_Password

A little reading of how Home Assistant handles these in the secretes.yaml file and I managed to get that set up without having to change those values. I think this is intended from yourself but for a newbie like me it wasn’t clear what I needed to do with those.

I understand now and thank-you for sharing your code with us and the above guide which allowed me to learn!

Also worth noting I have just successfully turned my light switch off and back on again using the two websites I linked above.

Don’t know if its worth mentioning but whilst using this for a couple of days, some of my sockets in Home Assistant started to switch themselves into the off position and become “unavailable” whilst the physical sockets were still on. After troubleshooting using the logs I found the following entry:-
2022-10-25 00:25:17.868 DEBUG (MainThread) [homeassistant.components.rest.sensor] Data fetched from resource: <!DOCTYPE html> 2022-10-25 00:25:17.869 WARNING (MainThread) [homeassistant.components.rest.sensor] REST result could not be parsed as JSON 2022-10-25 00:25:17.896 DEBUG (MainThread) [homeassistant.components.rest.sensor] Erroneous JSON: <!DOCTYPE html>

Note the webpage my Home Assistant is querying for JSON is -
https://mihome4u.co.uk/api/v1/subdevices/show
Normally the response from this api is in JSON format and the following is returned
{"status":"access-denied","time":null,"flags":{},"data":{"message":"Access to subdevices/show is not permitted."}}
this response is expected as I’m not logging in at this stage, just sending a query to the webpage using Chrome.
Initially this was driving me crazy as you can clearly see the response in Chrome is in JSON and never did I receive anything in HTML until…
I decided to hit the refresh button quickly and the same amount of times as I have sensors and note I get the following webpage


So this is where my error is coming from, the frequency of the queries to the MiHome api is limited by how many requests can be sent from the same IP address and in these instances a html webpage is returned therefore resulting in my switches being broken and the “REST result cant be parsed as JSON” error I was receiving in the logs.

My fix was to increment the scan_interval: 60 in the yaml config files by one second per sensor and now I dont get any unavailable sensors in my Home Assistant setup :grinning:

just wanted to say a big thanks…discovered this post today and was able to get all three adapters and my monitor plug all working as expected…brilliant…thanks so much

1 Like

This looks very interesting as I have a lot of Energenie stuff. I currently have smart plugs, light switches, eTRVs, and their whole home power monitor integrated with HA using command line switches and sensors along with curl command to read/update eTVRs. It works but is a bit clunky and needs a different curl command for every target temp on each eTVR as well as for each value I want to read from every device. I also have an couple of movement and door contact sensors that I haven’t bothered to integrate into HA yet. Has anyone managed to get anything beyond the switches working via this method please?

I would be happy to work with someone to try and expand the template files to the other devices, I am no programmer but am okay with yaml files :slight_smile:

1 Like

So as a test I got one or my eTRVs working:

sensor:
  - platform: rest
    name: "Office TRV"
    resource: 'https://mihome4u.co.uk/api/v1/subdevices/show'
    method: POST
    authentication: basic
    username: !secret MiHome_ID
    password: !secret MiHome_Password
    payload: '{"id":12345}'
    value_template: '{{ value_json.data.last_temperature }}'
    json_attributes_path: "data"
    json_attributes:
      - label
      - device_id
      - power_state
      - startup_mode
      - device_type
      - remote_id
      - target_temperature
      - voltage
      - voltage_reported_at
      - updated_at
      - nest_thermostat_id
      - energenie_thermostat_id
      - controlling_thermostat_id
      - optimise_warm_up_schedule
      - notifications_enabled
      - disconnected_at
      - online
      - reduce_target_temperature_at
      - last_temperature
    headers:
      Content-Type: application/json
    force_update: true
    scan_interval: 300

switch:  # Set up a switch to allow for setting on/off temperature
  - platform: template
    switches:
      mihome_office_trv_switch:
        friendly_name: "Office TRV Switch"
        availability_template: "{{ as_timestamp(now()) - as_timestamp(state_attr('sensor.office_trv', 'updated_at')) < 5400 }}" #Amended to be 1.5 hrs as eTRVs update once a hour
        turn_on:
          - service: rest_command.mihome_office_trv_switch_on # Call RESTful Command to set eTRV to 21 Degrees.
          - service: homeassistant.update_entity # Update switch status sensor now.
            target:
              entity_id: sensor.office_trv
        turn_off:
          - service: rest_command.mihome_office_trv_switch_off # Call RESTful Command to set eTRV to 16 Degrees.
          - service: homeassistant.update_entity
            target:
              entity_id: sensor.office_trv

rest_command:
  mihome_office_trv_switch_on:
    url: "https://mihome4u.co.uk/api/v1/subdevices/set_target_temperature"
    payload: '{"id":12345, "temperature":21.0}'
    method: POST
    content_type: application/json
    username: !secret MiHome_ID
    password: !secret MiHome_Password
  mihome_office_trv_switch_off:
    url: "https://mihome4u.co.uk/api/v1/subdevices/set_target_temperature"
    payload: '{"id":12345, "temperature":16.0}'
    method: POST
    content_type: application/json
    username: !secret MiHome_ID
    password: !secret MiHome_Password

I’m not sure if swapping over gives much advantage other than not having to set up a different sensor for each attribute (I use 3, Temp, Target Temp and Battery V) as I still needed to have a fixed on and off temp (although this allow easy creation of an On/Off switch). If starting a fresh setup then this is definitely a better approach. Now the killer would be if someone could make a slider/dial to set the temp on a card :slight_smile:

Thanks for posting this.

Hi,

After a few years of using the command state method i came across this and thought would give it a go with my light switches.

Pleased to say that the on / off functions work well and are significantly faster than the method i used before.

However the state of the device doesnt seem to be working properly. It updates as expected when the switches are turned on and off through HA but when it is done on the switch itself it doesnt seem to register the change.

has anyone else seen this behaviour ?

  # Kitchen Light Sensor
  - platform: rest
    name: "Kitchen Light Status"
    resource: 'https://mihome4u.co.uk/api/v1/subdevices/show'
    method: POST
    authentication: basic
    username: !secret MiHome_ID
    password: !secret MiHome_Password
    payload: '{"id":55855}'
    value_template: '{{ value_json.data.power_state }}'
    json_attributes_path: "data"
    json_attributes:
      - device_id
      - power_state
    headers:
      Content-Type: application/json
    force_update: true
    scan_interval: 54 

I did also have the JSON errors as mentioned above, but as stated when i incrimented the scan interval on each sensor by a second this problem went away.

Anyway that issue aside i have turned the kitchen light on manually at the switch, waited 5 mins and when I check the state of the light in home assistant it is still showing as off.

Any help appreciated if available

Thanks

Andrew

EDIT: If i call the update entity service on the sensor it still doesnt change to the correct status

This will be because the light switches do not report their state back to Energenie so the refresh will get the last state that their servers know about. I suspect if you use the Energenie app to switch them then they will report correctly in HA after the scan interval time. One of the limitations of one way comms switches unfortunately

1 Like

Right OK … by design then state is controlled by the app trigger.

Faire enough

image

I have managed to set these up using the “helpers” function in HomeAssistant. Im still messing around with this and theres a few things that need to be ironed out: -

  1. Change of temp in the MiHome app doesnt update the slider
  2. A restart of HASOS causes the sliders to go back to default 21 degrees when infact the eTrv may be set too something else

I placed this in my automations.yaml for each of the eTRV’s

- id: '1668895343411'
  alias: Down Bathroom eTRV Temp changed
  description: ''
  trigger:
  - platform: state
    entity_id: input_number.downbathroom_etrv
  condition: []
  action:
  - service: rest_command.mihome_######_settemp
    data:
      downbathroom_etrv: '{{ states(''input_number.downbathroom_etrv'') | int }}'
  mode: single

And this is one of my eTRV files: -

#########################################################################################
# Energenie MiHome https://energenie4u.co.uk/ 
# Rest API interface https://mihome4u.co.uk/docs/api-documentation
#########################################################################################
# Richard Huish 2022
#
# This replaces the examples many people provided using command_sensor / command_switch 
# with curl_commands.
#
# Notes: If you get  error message responses along the lines of:
#  ""message": "`id` should be a `Integer` but is a `String`"
#   double check you haven't accidentally put double quotes around the ID number.
#
# A very helpful website for debugging: https://reqbin.com/rest-api-testing / https://reqbin.com/req/v0crmky0/rest-api-post-example
# 
# Also, set the debugger to record all the detail about the rest components
# in order to then see any error messages in the error log.
#    logger:
#      logs:
#        homeassistant.components.rest: debug
#########################################################################################

###################################################################################################################
# MiHome Switch ID:###### Status Sensor
# Control and Monitor Mi|Home eTRV MIHO013
# Due to limitations with the RESTful switch integration (cannot have different resource URLs for on and off)
# I have had to create a templated switch.
# Sets the sensor as unavailable, if voltage_reported_at is more than 240 seconds ago.
###################################################################################################################

input_number:
  downbathroom_etrv:
    name: Down Bathroom eTRV
    initial: 21
    min: 12
    max: 30
    step: 0.5
    
rest_command:
  mihome_######_settemp_12:
    url: "https://mihome4u.co.uk/api/v1/subdevices/set_target_temperature"
    payload: '{"id":######,"temperature":12.0}'
    method: POST
    content_type: application/json
    username: !secret MiHome_ID
    password: !secret MiHome_Password
  mihome_######_settemp_21:
    url: "https://mihome4u.co.uk/api/v1/subdevices/set_target_temperature"
    payload: '{"id":######,"temperature":21.0}'
    method: POST
    content_type: application/json
    username: !secret MiHome_ID
    password: !secret MiHome_Password
  mihome_######_settemp:
    url: "https://mihome4u.co.uk/api/v1/subdevices/set_target_temperature"
    payload: '{"id":######,"temperature": {{downbathroom_etrv}} }'
    method: POST
    content_type: application/json
    username: !secret MiHome_ID
    password: !secret MiHome_Password

sensor:
  - platform: rest
    name: "MiHome DownBathroom eTRV Temp"
    unit_of_measurement: '°C'
    device_class: temperature
    state_class: measurement
    resource: 'https://mihome4u.co.uk/api/v1/subdevices/show'
    method: POST
    authentication: basic
    username: !secret MiHome_ID
    password: !secret MiHome_Password
    payload: '{"id":######}'
    value_template: '{{ value_json.data.last_temperature | float }}'
    json_attributes_path: "data"
    json_attributes:
      - label
      - device_id
      - power_state
      - startup_mode
      - device_type
      - remote_id
      - target_temperature
      - voltage
      - voltage_reported_at
      - updated_at
      - last_temperature
      
    headers:
      Content-Type: application/json
    force_update: true
    scan_interval: 67

# https://www.home-assistant.io/integrations/integration/
# https://community.home-assistant.io/t/powercalc-virtual-power-sensors/318515/3
# https://www.home-assistant.io/integrations/integration/#energy
#  - platform: integration
#    source: sensor.mihome_washer_switch_watts
#    name: MiHome Washer Switch Energy
#    unit_prefix: k
#    unit_time: h
#    round: 2

template: # https://www.home-assistant.io/integrations/template/#state-based-template-sensors
  - sensor: #Use a template to create the temperature sensor, rather than an additional rest sensor, to reduce web queries to the mihome server
      - name: "MiHome Down Bathroom eTRV Targ Temp"
        # friendly_name: "MiHome Ice Maker Watts2"
        state: "{{ state_attr('sensor.mihome_downbathroom_etrv_temp', 'target_temperature') | float }}"
        # availability_template: "{{(now() - state_attr('sensor.mihome_######_switch_status', 'voltage_reported_at') | as_datetime).seconds < 240}}"
        unit_of_measurement: '°C'
        device_class: temperature #Power, watts. Not "Energy" i.e. Wh.
        state_class: measurement
  - sensor: #Use a template to create the temperature sensor, rather than an additional rest sensor, to reduce web queries to the mihome server
      - name: "MiHome Down Bathroom eTRV Voltage"
        # friendly_name: "MiHome Ice Maker Watts2"
        state: "{{ state_attr('sensor.mihome_downbathroom_etrv_temp', 'voltage') | float}}"
        # availability_template: "{{(now() - state_attr('sensor.mihome_######_switch_status', 'voltage_reported_at') | as_datetime).seconds < 240}}"
        unit_of_measurement: 'V'
        device_class: voltage #Power, watts. Not "Energy" i.e. Wh.
        state_class: measurement
1 Like

Happy to assist where I can, got a few things from MiHome integrated into HASOS and im pretty confident I could do more. My next purchase is going to be some door and motion sensors but im unsure if im going to buy the MiHome ones.

You can get some devices from Energenie that do report status back, for example I have some of the power monitoring sockets and they respond back with socket status but not all of their devices can do this.

I have both of this and am selling/swapping them out. They work fine in the Energenie eco system but as these HA integrations rely on polling to get the state, unless you were polling every second or so, which I think their API my block, then HA often doesn’t notice they have been triggered and certainly no in a short enough time to make automations any use

Thanks for this, I definitely need to give it a go! :slight_smile: Need to have a think to get my head round it a bit more but it should be possible to update the number helper form the sensor value as well. Trick will be the timing I think…

OK so I got it working with just a 2nd reverse automation that updates the slider with the energenie value changes so now they stay in sync

id: '1681565586845'
  alias: Rads - Slider Office Update
  description: ''
  trigger:
  - platform: state
    entity_id:
    - sensor.office_rad_target
    enabled: true
  condition: []
  action:
  - service: input_number.set_value
    data:
      value: '{{ states(''sensor.office_rad_target'') | int }}'
    target:
      entity_id: input_number.office_etrv
    enabled: true
  mode: single

Here is my first go at a card that displays the current and target temp and can change the target using the slider when clicked on. Just with the Office eTRV for now:

When you click on the “target” the slider helper comes up to adjust the temp

Okay, so now I have found a tidier (I think) way of displaying and controlling them in HA and doesn’t need the automations. This custom integration in HACS can make a climate entity from a number of other single sensors and execute a script to control the temp

Basically it will take the actual and target temps from either the command line or Rest sensors you have and then I used the REST service that @leonness posted above to adjust the temp. The new climate entity it then displayed and controlled in Lovelace just like any other. If anyone is interested I can post the code I used on mine

1 Like