Open leva0887 opened 3 years ago
Hi, That model is in fact unsupported by my code. If someone wishes to extend it and create a pull request, I would be more that happy :)
zb1 isnt showing up also. i guess the code isnt working at all anymore. i retreived the token put in the ip and name in the configuration file installed the custom component en rebooted Hass. no error but heater isnt showing up in hass. I think the code is no longer working. the whole integration in HACS cant be found also. only a chinese version. so maybe this is discontinued
I saw your comment in HA community that it’s working with your version, so I’m gonna keep that one as supported. am I right?
YES! its working. What i did see is that when you activate the heater within HA and it reaches its target temperature it turns itself off and not on anymore when the temperature has dropped. So i think its a seperate way of turning on the heater?
That is weird. It doesn’t happen with my version :(
So normally the heater would turn off when a temp has reached and back on when it drops below that temp right?
In my case, with Xiaomi Space Heater S, when it reaches the temperature it just reduces power, does not turn off, to maintain the desired temperature. I can see this power change via a smart plug. This happens regardless if I configure it via HA or via Xiaomi App.
Hi, That model is in fact unsupported by my code. If someone wishes to extend it and create a pull request, I would be more that happy :)
What we need to do so that you add to ZA1 code?Thank you!
Well… if I had the heater, I would try myself. As an alternative, the code is open, and someone who has it, can modify the code and include support for it.
I have been using the code and sending commands to node red. But I too don't have the za1. I saw on your code that you use raw command to send the commands. How did you manage to get the commands for the heater?
Well… if I had the heater, I would try myself. As an alternative, the code is open, and someone who has it, can modify the code and include support for it.
I am ready to try, but I am not familiar with Python.Where and what you need to change?
in climate.py search for "self._device.raw_command" the info behind it are the commands send to the heater. The only thing now to do is find out what the commands for your heater are... like i asked before we need to know how @ee02217 did manage to get the commands out. As soon as you know what the commands need to be you can start adding them.
In node red i manages to turn the zb1 on by sending this code to it:
{
"cmd": "miio",
"method": "set_properties",
"value": [
{
"value": true,
"siid": 2,
"piid": 2
}
]
}
and off is this command:
{
"cmd": "miio",
"method": "set_properties",
"value": [
{
"value": false,
"siid": 2,
"piid": 2
}
]
}
There is also the get_properties ability with different commands like list. But i seem to get an error. So im not sure how to ask the heater to give it info.
It would be great if ee02217 is willing to share how he did the reverse engineering. here is some info on how to retreive data: https://github.com/rytilahti/python-miio
And this is a very important site which explains how to issue commands. I had allot of help on that one. but its all in chinese so just look at the commands: https://github.com/YinHangCode/node-red-contrib-mi-miio
The reason i want to control the heater without the integration is because it somehow lags HA when its running. I want to remove the integration and do all this in node red.
When doing the list command, the problem is i get an emty array so i guess this option isnt supported by the heater.
I got this from this url: https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:heater:0000A01A:zhimi-za1:1
got there from a lot of googling :)
i can imagine that! wow this is well hided. And the normal url witout the extras wont get you anywhere so you really need the whole link. when you change "A:zhimi-za1:1" to "A:zhimi-zb1:1" i see i get my heater
to make it more readable:
{
"type": "urn:miot-spec-v2:device:heater:0000A01A:zhimi-za1:1",
"description": "Heater",
"services": [
{
"iid": 1,
"type": "urn:miot-spec-v2:service:device-information:00007801:zhimi-za1:1",
"description": "Device Information",
"properties": [
{
"iid": 1,
"type": "urn:miot-spec-v2:property:manufacturer:00000001:zhimi-za1:1",
"description": "Device Manufacturer",
"format": "string",
"access": [
"read"
]
},
{
"iid": 2,
"type": "urn:miot-spec-v2:property:model:00000002:zhimi-za1:1",
"description": "Device Model",
"format": "string",
"access": [
"read"
]
},
{
"iid": 3,
"type": "urn:miot-spec-v2:property:serial-number:00000003:zhimi-za1:1",
"description": "Device Serial Number",
"format": "string",
"access": [
"read"
]
},
{
"iid": 4,
"type": "urn:miot-spec-v2:property:firmware-revision:00000005:zhimi-za1:1",
"description": "Current Firmware Version",
"format": "string",
"access": [
"read"
]
}
]
},
{
"iid": 2,
"type": "urn:miot-spec-v2:service:heater:0000782E:zhimi-za1:1",
"description": "Heater",
"properties": [
{
"iid": 1,
"type": "urn:miot-spec-v2:property:on:00000006:zhimi-za1:1",
"description": "Switch Status",
"format": "bool",
"access": [
"read",
"write",
"notify"
]
},
{
"iid": 2,
"type": "urn:miot-spec-v2:property:target-temperature:00000021:zhimi-za1:1",
"description": "Target Temperature",
"format": "float",
"access": [
"read",
"write",
"notify"
],
"unit": "celsius",
"value-range": [
16,
32,
1
]
}
]
},
{
"iid": 3,
"type": "urn:miot-spec-v2:service:environment:0000780A:zhimi-za1:1",
"description": "Environment",
"properties": [
{
"iid": 1,
"type": "urn:miot-spec-v2:property:temperature:00000020:zhimi-za1:1",
"description": "Temperature",
"format": "float",
"access": [
"read",
"notify"
],
"unit": "celsius",
"value-range": [
-40,
125,
0.1
]
},
{
"iid": 2,
"type": "urn:miot-spec-v2:property:relative-humidity:0000000C:zhimi-za1:1",
"description": "Relative Humidity",
"format": "uint8",
"access": [
"read",
"notify"
],
"unit": "percentage",
"value-range": [
0,
100,
1
]
}
]
},
{
"iid": 4,
"type": "urn:miot-spec-v2:service:physical-controls-locked:00007807:zhimi-za1:1",
"description": "Physical Control Locked",
"properties": [
{
"iid": 1,
"type": "urn:miot-spec-v2:property:physical-controls-locked:0000001D:zhimi-za1:1",
"description": "Physical Control Locked",
"format": "bool",
"access": [
"read",
"write",
"notify"
]
}
]
},
{
"iid": 5,
"type": "urn:miot-spec-v2:service:alarm:00007804:zhimi-za1:1",
"description": "Alarm",
"properties": [
{
"iid": 1,
"type": "urn:miot-spec-v2:property:alarm:00000012:zhimi-za1:1",
"description": "Alarm",
"format": "bool",
"access": [
"read",
"write",
"notify"
]
}
]
}
]
}
For getting the temperature i need those 2 values: "siid": 2, "piid": 6
When looking in the code i only see iid: 6
Where does the p stands for? properties? and s in siid seem to stand for services. How did you manage to find that out :)
Man you have put in allot of work just trying to find out the commands alone lol
But reading this controlling the za1 shouldnt be that big of a deal now. atleast not when importing it in Node red.
I removed the integration and no more freezes anymore so i still think the smartmi integration causes some serious lag behind the scenes.
True… it was a lot of trial and error… covid got me stuck at home… I picked other existing integrations and just started changing values.
to make it more readable:
{ "type": "urn:miot-spec-v2:device:heater:0000A01A:zhimi-za1:1", "description": "Heater", "services": [ { "iid": 1, "type": "urn:miot-spec-v2:service:device-information:00007801:zhimi-za1:1", "description": "Device Information", "properties": [ { "iid": 1, "type": "urn:miot-spec-v2:property:manufacturer:00000001:zhimi-za1:1", "description": "Device Manufacturer", "format": "string", "access": [ "read" ] }, { "iid": 2, "type": "urn:miot-spec-v2:property:model:00000002:zhimi-za1:1", "description": "Device Model", "format": "string", "access": [ "read" ] }, { "iid": 3, "type": "urn:miot-spec-v2:property:serial-number:00000003:zhimi-za1:1", "description": "Device Serial Number", "format": "string", "access": [ "read" ] }, { "iid": 4, "type": "urn:miot-spec-v2:property:firmware-revision:00000005:zhimi-za1:1", "description": "Current Firmware Version", "format": "string", "access": [ "read" ] } ] }, { "iid": 2, "type": "urn:miot-spec-v2:service:heater:0000782E:zhimi-za1:1", "description": "Heater", "properties": [ { "iid": 1, "type": "urn:miot-spec-v2:property:on:00000006:zhimi-za1:1", "description": "Switch Status", "format": "bool", "access": [ "read", "write", "notify" ] }, { "iid": 2, "type": "urn:miot-spec-v2:property:target-temperature:00000021:zhimi-za1:1", "description": "Target Temperature", "format": "float", "access": [ "read", "write", "notify" ], "unit": "celsius", "value-range": [ 16, 32, 1 ] } ] }, { "iid": 3, "type": "urn:miot-spec-v2:service:environment:0000780A:zhimi-za1:1", "description": "Environment", "properties": [ { "iid": 1, "type": "urn:miot-spec-v2:property:temperature:00000020:zhimi-za1:1", "description": "Temperature", "format": "float", "access": [ "read", "notify" ], "unit": "celsius", "value-range": [ -40, 125, 0.1 ] }, { "iid": 2, "type": "urn:miot-spec-v2:property:relative-humidity:0000000C:zhimi-za1:1", "description": "Relative Humidity", "format": "uint8", "access": [ "read", "notify" ], "unit": "percentage", "value-range": [ 0, 100, 1 ] } ] }, { "iid": 4, "type": "urn:miot-spec-v2:service:physical-controls-locked:00007807:zhimi-za1:1", "description": "Physical Control Locked", "properties": [ { "iid": 1, "type": "urn:miot-spec-v2:property:physical-controls-locked:0000001D:zhimi-za1:1", "description": "Physical Control Locked", "format": "bool", "access": [ "read", "write", "notify" ] } ] }, { "iid": 5, "type": "urn:miot-spec-v2:service:alarm:00007804:zhimi-za1:1", "description": "Alarm", "properties": [ { "iid": 1, "type": "urn:miot-spec-v2:property:alarm:00000012:zhimi-za1:1", "description": "Alarm", "format": "bool", "access": [ "read", "write", "notify" ] } ] } ] }
this code is for whom? where to insert it?
That is not code. Those are just the values needed to use in the code.
@ee02217 Is this just as easy as adding this to the code to make it work for za1:
if self._model == "zhimi.heater.mc2":
self._device.raw_command('set_properties',[{"value":False,"siid":2,"piid":1, "did":DEVICE_ID}])
elif self._model == "zhimi.heater.zb1" or self._model == "zhimi.heater.za2" :
self._device.raw_command('set_properties',[{"value":False,"siid":2,"piid":2}])
elif self._model == "zhimi.heater.za1" :
self._device.raw_command('set_properties',[{"value":False,"siid":2,"piid":1}])
else:
_LOGGER.exception('Unsupported model: %s', self._model)
and do this for all the raw commands in your climate.py
This is 5 minutes of work to get it working for the za1
If im correct then above i just added support for the za1 to turn it off
I could help with this adding all these lines to the code. But i need to be sure its correct and the only thing that needs to be done. I dont want to break anyone's config...
@droserHA This should be the code to put in climate.py for support of the zhimi.heater.za1
Make a backup before you use this. i have no experience in making integrations only changed the code in which i think it should work. Maybe @ee02217 can do a last check.
You need to check what your minimum temp of the heater is. if its not 16 then the code need another change. Let me know and dont use this code before you checked that.
"""
Support for Xiaomi wifi-enabled home heaters via miio.
author: sunfang1cn@gmail.com
modifier: ee02217
Tested environment: HASS 0.118.5
"""
import logging
import voluptuous as vol
from homeassistant.components.climate import ClimateEntity, PLATFORM_SCHEMA
from homeassistant.components.climate.const import (
DOMAIN, HVAC_MODE_HEAT,HVAC_MODE_COOL, HVAC_MODE_OFF,
SUPPORT_TARGET_TEMPERATURE, SUPPORT_FAN_MODE)
from homeassistant.const import (
ATTR_TEMPERATURE, CONF_HOST, CONF_NAME, CONF_TOKEN, CONF_DEVICE_ID,
STATE_ON, STATE_OFF, TEMP_CELSIUS)
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.entity import generate_entity_id
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.exceptions import PlatformNotReady
from miio import Device,DeviceException
_LOGGER = logging.getLogger(__name__)
CONF_MODEL = 'model'
REQUIREMENTS = ['python-miio>=0.5.0']
SUPPORT_FLAGS = (SUPPORT_TARGET_TEMPERATURE)
SERVICE_SET_ROOM_TEMP = 'miheater_set_room_temperature'
PRECISION = 1
MIN_TEMP = 18
MIN_TEMP_ZB1 = 16
MAX_TEMP = 28
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_HOST): cv.string,
vol.Required(CONF_NAME): cv.string,
vol.Required(CONF_TOKEN): cv.string,
vol.Optional(CONF_DEVICE_ID): cv.string,
vol.Optional(CONF_MODEL, default=None): vol.In(
['zhimi.heater.mc2',
'zhimi.heater.zb1',
'zhimi.heater.za2',
'zhimi.heater.za1', None]),
})
SET_ROOM_TEMP_SCHEMA = vol.Schema({
vol.Optional('temperature'): cv.positive_int
})
DEVICE_MODEL = ""
ATTR_MODEL = 'model'
DEVICE_ID = ""
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Perform the setup for Xiaomi heaters."""
host = config.get(CONF_HOST)
name = config.get(CONF_NAME)
token = config.get(CONF_TOKEN)
model = config.get(CONF_MODEL)
DEVICE_ID = config.get(CONF_DEVICE_ID)
_LOGGER.info("Initializing Xiaomi heaters with host %s (token %s...)", host, token[:5])
devices = []
unique_id = None
try:
device = Device(host, token)
device_info = device.info()
if model is None:
model = device_info.model
DEVICE_MODEL = model
unique_id = "{}-{}".format(model, device_info.mac_address)
_LOGGER.warning("%s %s %s detected",
model,
device_info.firmware_version,
device_info.hardware_version)
miHeater = MiHeater(device, name, model, unique_id, hass)
devices.append(miHeater)
add_devices(devices)
async def set_room_temp(service):
"""Set room temp."""
if DEVICE_MODEL == "zhimi.heater.mc2":
aux = device.raw_command('get_properties', [{"siid":2,"piid":5,"did":DEVICE_ID}])
elif DEVICE_MODEL == "zhimi.heater.zb1" or DEVICE_MODEL == "zhimi.heater.za2":
aux = device.raw_command('get_properties', [{"siid":2,"piid":6}])
elif DEVICE_MODEL == "zhimi.heater.za1":
aux = device.raw_command('get_properties', [{"siid":3,"piid":1}])
else :
_LOGGER.exception('Unsupported model: %s', DEVICE_MODEL)
temperature=aux[0]["value"]
await miHeater.async_set_temperature(temperature)
hass.services.async_register(DOMAIN, SERVICE_SET_ROOM_TEMP,
set_room_temp, schema=SET_ROOM_TEMP_SCHEMA)
except DeviceException:
_LOGGER.exception('Fail to setup Xiaomi heater')
raise PlatformNotReady
class MiHeater(ClimateEntity):
"""Representation of a MiHeater device."""
def __init__(self, device, name, model, unique_id, _hass):
"""Initialize the heater."""
self._device = device
self._name = name
self._model = model
self._state = None
self.entity_id = generate_entity_id('climate.{}', unique_id, hass=_hass)
self.getAttrData()
@property
def name(self):
"""Return the name of the device."""
return self._name
@property
def device(self):
"""Return the model of the device."""
return self._model
@property
def hvac_mode(self):
return HVAC_MODE_HEAT if self._state['power'] else HVAC_MODE_OFF
@property
def hvac_modes(self):
return [HVAC_MODE_HEAT, HVAC_MODE_OFF]
@property
def supported_features(self):
"""Return the list of supported features."""
return SUPPORT_FLAGS
@property
def temperature_unit(self):
"""Return the unit of measurement which this thermostat uses."""
return TEMP_CELSIUS
# @property
# def precision(self):
# """Return the unit of measurement which this thermostat uses."""
# return PRECISION
@property
def target_temperature(self):
"""Return the temperature we try to reach."""
return self._state['target_temperature']
@property
def current_temperature(self):
"""Return the current temperature."""
return self._state['current_temperature']
@property
def current_humidity(self):
"""Return the current humidity."""
return self._state['humidity']
@property
def target_temperature_step(self):
"""Return the supported step of target temperature."""
return 1
def getAttrData(self):
try:
data = {}
#device_info = self._device.info()
#DEVICE_MODEL = device_info.model
if self._model == "zhimi.heater.mc2":
power=self._device.raw_command('get_properties', [{"did":DEVICE_ID,"siid":2,"piid":1}])
target_temperature=self._device.raw_command('get_properties', [{"did":DEVICE_ID,"siid":2,"piid":5}])
current_temperature=self._device.raw_command('get_properties', [{"did":DEVICE_ID,"siid":4,"piid":7}])
data['humidity'] = 0
elif self._model == "zhimi.heater.zb1" or self._model == "zhimi.heater.za2" :
power=self._device.raw_command('get_properties', [{"siid":2,"piid":2}])
humidity=self._device.raw_command('get_properties', [{"siid":5,"piid":7}])
target_temperature=self._device.raw_command('get_properties', [{"siid":2,"piid":6}])
current_temperature=self._device.raw_command('get_properties', [{"siid":5,"piid":8}])
data['humidity'] = humidity[0]["value"]
elif self._model == "zhimi.heater.za1" :
power=self._device.raw_command('get_properties', [{"siid":2,"piid":1}])
humidity=self._device.raw_command('get_properties', [{"siid":3,"piid":2}])
target_temperature=self._device.raw_command('get_properties', [{"siid":2,"piid":2}])
current_temperature=self._device.raw_command('get_properties', [{"siid":3,"piid":1}])
data['humidity'] = humidity[0]["value"]
else:
_LOGGER.exception('Unsupported model: %s', self._model)
data['power'] = power[0]["value"]
data['target_temperature'] = target_temperature[0]["value"]
data['current_temperature'] = current_temperature[0]["value"]
self._state = data
except DeviceException:
_LOGGER.exception('Fail to get_prop from Xiaomi heater')
self._state = None
raise PlatformNotReady
@property
def device_state_attributes(self):
return self._state
@property
def is_on(self):
"""Return true if heater is on."""
return self._state['power']
@property
def min_temp(self):
"""Return the minimum temperature."""
if self._model == "zhimi.heater.zb1" or self._model == "zhimi.heater.za2" or self._model == "zhimi.heater.za1" :
return MIN_TEMP_ZB1
else:
return MIN_TEMP
@property
def max_temp(self):
"""Return the maximum temperature."""
return MAX_TEMP
async def async_set_temperature(self, **kwargs):
"""Set new target temperature."""
temperature = kwargs.get(ATTR_TEMPERATURE)
_LOGGER.warning("Setting temperature: %s", int(temperature))
if temperature is None:
_LOGGER.error("Wrong temperature: %s", temperature)
return
#device_info = self._device.info()
#DEVICE_MODEL = device_info.model
if self._model == "zhimi.heater.mc2":
self._device.raw_command('set_properties',[{"value":int(temperature),"siid":2,"piid":5, "did":DEVICE_ID}])
elif self._model == "zhimi.heater.zb1" or self._model == "zhimi.heater.za2" :
self._device.raw_command('set_properties',[{"value":int(temperature),"siid":2,"piid":6}])
elif self._model == "zhimi.heater.za1" :
self._device.raw_command('set_properties',[{"value":int(temperature),"siid":2,"piid":2}])
else:
_LOGGER.exception('Unsupported model: %s', self._model)
async def async_turn_on(self):
"""Turn Mill unit on."""
#device_info = self._device.info()
#DEVICE_MODEL = device_info.model
if self._model == "zhimi.heater.mc2":
self._device.raw_command('set_properties',[{"value":True,"siid":2,"piid":1, "did":DEVICE_ID}])
elif self._model == "zhimi.heater.zb1" or self._model == "zhimi.heater.za2" :
self._device.raw_command('set_properties',[{"value":True,"siid":2,"piid":2}])
elif self._model == "zhimi.heater.za1" :
self._device.raw_command('set_properties',[{"value":True,"siid":2,"piid":1}])
else:
_LOGGER.exception('Unsupported model: %s', self._model)
async def async_turn_off(self):
"""Turn Mill unit off."""
#device_info = self._device.info()
#DEVICE_MODEL = device_info.model
if self._model == "zhimi.heater.mc2":
self._device.raw_command('set_properties',[{"value":False,"siid":2,"piid":1, "did":DEVICE_ID}])
elif self._model == "zhimi.heater.zb1" or self._model == "zhimi.heater.za2" :
self._device.raw_command('set_properties',[{"value":False,"siid":2,"piid":2}])
elif self._model == "zhimi.heater.za1" :
self._device.raw_command('set_properties',[{"value":False,"siid":2,"piid":1}])
else:
_LOGGER.exception('Unsupported model: %s', self._model)
async def async_update(self):
"""Retrieve latest state."""
self.getAttrData()
async def async_set_hvac_mode(self, hvac_mode):
"""Set operation mode."""
if hvac_mode == HVAC_MODE_HEAT or hvac_mode == HVAC_MODE_COOL:
await self.async_turn_on()
elif hvac_mode == HVAC_MODE_OFF:
await self.async_turn_off()
else:
_LOGGER.error("Unrecognized operation mode: %s", hvac_mode)
I have za1 and mihome with brakes and servers in china. I can participate in testing with my za1.Отправлено с устройства Galaxy -------- Исходное сообщение --------От: sygys @.> Дата: 29.09.2021 09:40 (GMT+02:00) Кому: ee02217/homeassistant-mi-heater @.> Копия: droserHA @.>, Comment @.> Тема: Re: [ee02217/homeassistant-mi-heater] Not work on zhimi.heater.za1 (#6) I could help with this adding all these lines to the code. But i need to be sure its correct and the only thing that needs to be done. I dont want to break anyone's config...
—You are receiving this because you commented.Reply to this email directly, view it on GitHub, or unsubscribe.Triage notifications on the go with GitHub Mobile for iOS or Android.
First check the minimum temp the heater can be set on. if its 16 the code should work.... it doesnt care which server your on. you are going to command the heater locally you do need the token.
I allready added all the lines in the code that you should need for your heater.
If this confirms to work @ee02217 can edit the code so everyone can use it.
First check the minimum temp the heater can be set on. if its 16 the code should work.... it doesnt care which server your on. you are going to command the heater locally you do need the token.
I allready added all the lines in the code that you should need for your heater.
If this confirms to work @ee02217 can edit the code so everyone can use it.
Hi @sygys , You can directly change the code. I made it public for that. Please change ir directly and make a merge request ;)
I’m away from the PC for a while and this way you guys can test it sooner.
No problem first i need to know if it all works then i will do a merge request... first time doing all this so bare with me if it doesnt work...
besides all this i need to try and find out whats causing the lag in home assistant filesystem when this integration is active. Since i removed it i dont have any lag in my home assistant. Something in the climate.py code is causing home assistant to freeze every few seconds. Im not really sure its only the zb1 heater part or what is causing it. i will dive into the code and test it on a spare home assistant server soon. maybe i can find out what is causing the freezes.
This is why i removed this integration for now and using node red to turn the heater on and off
Wow. To be honest, I haven’t felt that issue, but I a, running it in a nuc, so it has a lot of power, which may be why I didn’t find it. If you find any issue it would be great.
PS- this was my first python programming, so it may be some sort of Frankenstein code :D
Im running home assistant on a i7 server pc with a very fast ssd. so i dont think that could be it. Its not that home assistant is slow in use. but scrolling through files using the file editor is. Sometimes when opening a yaml file it takes a few seconds. also saving files sometimes has a hickup and it takes a few seconds for the pop up file saved to show up. I cant really figure it out but i also have a feeling automations sometimes had a hickup. lights turning on a few seconds later through motion then expected. and all that kind of stuff. First i thought it was my zigbee network or coordinator being slow. but since i stopped using the integration it has been very stable. And everything fires instantly so i really think its this integration..
I will test it. and report back if i find anything. thanks so far for everything. Thanks to you i am beginning to understand how all this works.
What i was wondering is where the update interval is set? Or does home assistant set this itself? When using the integration i had allot of errors: Fail to get_prop from Xiaomi heater.
I want to find out why i get these errors.
I found nothing in other codes related to that. So I assume HA has come default for these.
@droserHA This should be the code to put in climate.py for support of the zhimi.heater.za1
Make a backup before you use this. i have no experience in making integrations only changed the code in which i think it should work. Maybe @ee02217 can do a last check.
You need to check what your minimum temp of the heater is. if its not 16 then the code need another change. Let me know and dont use this code before you checked that.
""" Support for Xiaomi wifi-enabled home heaters via miio. author: sunfang1cn@gmail.com modifier: ee02217 Tested environment: HASS 0.118.5 """ import logging import voluptuous as vol from homeassistant.components.climate import ClimateEntity, PLATFORM_SCHEMA from homeassistant.components.climate.const import ( DOMAIN, HVAC_MODE_HEAT,HVAC_MODE_COOL, HVAC_MODE_OFF, SUPPORT_TARGET_TEMPERATURE, SUPPORT_FAN_MODE) from homeassistant.const import ( ATTR_TEMPERATURE, CONF_HOST, CONF_NAME, CONF_TOKEN, CONF_DEVICE_ID, STATE_ON, STATE_OFF, TEMP_CELSIUS) from homeassistant.helpers import config_validation as cv from homeassistant.helpers.entity import generate_entity_id from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.exceptions import PlatformNotReady from miio import Device,DeviceException _LOGGER = logging.getLogger(__name__) CONF_MODEL = 'model' REQUIREMENTS = ['python-miio>=0.5.0'] SUPPORT_FLAGS = (SUPPORT_TARGET_TEMPERATURE) SERVICE_SET_ROOM_TEMP = 'miheater_set_room_temperature' PRECISION = 1 MIN_TEMP = 18 MIN_TEMP_ZB1 = 16 MAX_TEMP = 28 PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_HOST): cv.string, vol.Required(CONF_NAME): cv.string, vol.Required(CONF_TOKEN): cv.string, vol.Optional(CONF_DEVICE_ID): cv.string, vol.Optional(CONF_MODEL, default=None): vol.In( ['zhimi.heater.mc2', 'zhimi.heater.zb1', 'zhimi.heater.za2', 'zhimi.heater.za1', None]), }) SET_ROOM_TEMP_SCHEMA = vol.Schema({ vol.Optional('temperature'): cv.positive_int }) DEVICE_MODEL = "" ATTR_MODEL = 'model' DEVICE_ID = "" def setup_platform(hass, config, add_devices, discovery_info=None): """Perform the setup for Xiaomi heaters.""" host = config.get(CONF_HOST) name = config.get(CONF_NAME) token = config.get(CONF_TOKEN) model = config.get(CONF_MODEL) DEVICE_ID = config.get(CONF_DEVICE_ID) _LOGGER.info("Initializing Xiaomi heaters with host %s (token %s...)", host, token[:5]) devices = [] unique_id = None try: device = Device(host, token) device_info = device.info() if model is None: model = device_info.model DEVICE_MODEL = model unique_id = "{}-{}".format(model, device_info.mac_address) _LOGGER.warning("%s %s %s detected", model, device_info.firmware_version, device_info.hardware_version) miHeater = MiHeater(device, name, model, unique_id, hass) devices.append(miHeater) add_devices(devices) async def set_room_temp(service): """Set room temp.""" if DEVICE_MODEL == "zhimi.heater.mc2": aux = device.raw_command('get_properties', [{"siid":2,"piid":5,"did":DEVICE_ID}]) elif DEVICE_MODEL == "zhimi.heater.zb1" or DEVICE_MODEL == "zhimi.heater.za2": aux = device.raw_command('get_properties', [{"siid":2,"piid":6}]) elif DEVICE_MODEL == "zhimi.heater.za1": aux = device.raw_command('get_properties', [{"siid":3,"piid":1}]) else : _LOGGER.exception('Unsupported model: %s', DEVICE_MODEL) temperature=aux[0]["value"] await miHeater.async_set_temperature(temperature) hass.services.async_register(DOMAIN, SERVICE_SET_ROOM_TEMP, set_room_temp, schema=SET_ROOM_TEMP_SCHEMA) except DeviceException: _LOGGER.exception('Fail to setup Xiaomi heater') raise PlatformNotReady class MiHeater(ClimateEntity): """Representation of a MiHeater device.""" def __init__(self, device, name, model, unique_id, _hass): """Initialize the heater.""" self._device = device self._name = name self._model = model self._state = None self.entity_id = generate_entity_id('climate.{}', unique_id, hass=_hass) self.getAttrData() @property def name(self): """Return the name of the device.""" return self._name @property def device(self): """Return the model of the device.""" return self._model @property def hvac_mode(self): return HVAC_MODE_HEAT if self._state['power'] else HVAC_MODE_OFF @property def hvac_modes(self): return [HVAC_MODE_HEAT, HVAC_MODE_OFF] @property def supported_features(self): """Return the list of supported features.""" return SUPPORT_FLAGS @property def temperature_unit(self): """Return the unit of measurement which this thermostat uses.""" return TEMP_CELSIUS # @property # def precision(self): # """Return the unit of measurement which this thermostat uses.""" # return PRECISION @property def target_temperature(self): """Return the temperature we try to reach.""" return self._state['target_temperature'] @property def current_temperature(self): """Return the current temperature.""" return self._state['current_temperature'] @property def current_humidity(self): """Return the current humidity.""" return self._state['humidity'] @property def target_temperature_step(self): """Return the supported step of target temperature.""" return 1 def getAttrData(self): try: data = {} #device_info = self._device.info() #DEVICE_MODEL = device_info.model if self._model == "zhimi.heater.mc2": power=self._device.raw_command('get_properties', [{"did":DEVICE_ID,"siid":2,"piid":1}]) target_temperature=self._device.raw_command('get_properties', [{"did":DEVICE_ID,"siid":2,"piid":5}]) current_temperature=self._device.raw_command('get_properties', [{"did":DEVICE_ID,"siid":4,"piid":7}]) data['humidity'] = 0 elif self._model == "zhimi.heater.zb1" or self._model == "zhimi.heater.za2" : power=self._device.raw_command('get_properties', [{"siid":2,"piid":2}]) humidity=self._device.raw_command('get_properties', [{"siid":5,"piid":7}]) target_temperature=self._device.raw_command('get_properties', [{"siid":2,"piid":6}]) current_temperature=self._device.raw_command('get_properties', [{"siid":5,"piid":8}]) data['humidity'] = humidity[0]["value"] elif self._model == "zhimi.heater.za1" : power=self._device.raw_command('get_properties', [{"siid":2,"piid":1}]) humidity=self._device.raw_command('get_properties', [{"siid":3,"piid":2}]) target_temperature=self._device.raw_command('get_properties', [{"siid":2,"piid":2}]) current_temperature=self._device.raw_command('get_properties', [{"siid":3,"piid":1}]) data['humidity'] = humidity[0]["value"] else: _LOGGER.exception('Unsupported model: %s', self._model) data['power'] = power[0]["value"] data['target_temperature'] = target_temperature[0]["value"] data['current_temperature'] = current_temperature[0]["value"] self._state = data except DeviceException: _LOGGER.exception('Fail to get_prop from Xiaomi heater') self._state = None raise PlatformNotReady @property def device_state_attributes(self): return self._state @property def is_on(self): """Return true if heater is on.""" return self._state['power'] @property def min_temp(self): """Return the minimum temperature.""" if self._model == "zhimi.heater.zb1" or self._model == "zhimi.heater.za2" or self._model == "zhimi.heater.za1" : return MIN_TEMP_ZB1 else: return MIN_TEMP @property def max_temp(self): """Return the maximum temperature.""" return MAX_TEMP async def async_set_temperature(self, **kwargs): """Set new target temperature.""" temperature = kwargs.get(ATTR_TEMPERATURE) _LOGGER.warning("Setting temperature: %s", int(temperature)) if temperature is None: _LOGGER.error("Wrong temperature: %s", temperature) return #device_info = self._device.info() #DEVICE_MODEL = device_info.model if self._model == "zhimi.heater.mc2": self._device.raw_command('set_properties',[{"value":int(temperature),"siid":2,"piid":5, "did":DEVICE_ID}]) elif self._model == "zhimi.heater.zb1" or self._model == "zhimi.heater.za2" : self._device.raw_command('set_properties',[{"value":int(temperature),"siid":2,"piid":6}]) elif self._model == "zhimi.heater.za1" : self._device.raw_command('set_properties',[{"value":int(temperature),"siid":2,"piid":2}]) else: _LOGGER.exception('Unsupported model: %s', self._model) async def async_turn_on(self): """Turn Mill unit on.""" #device_info = self._device.info() #DEVICE_MODEL = device_info.model if self._model == "zhimi.heater.mc2": self._device.raw_command('set_properties',[{"value":True,"siid":2,"piid":1, "did":DEVICE_ID}]) elif self._model == "zhimi.heater.zb1" or self._model == "zhimi.heater.za2" : self._device.raw_command('set_properties',[{"value":True,"siid":2,"piid":2}]) elif self._model == "zhimi.heater.za1" : self._device.raw_command('set_properties',[{"value":True,"siid":2,"piid":1}]) else: _LOGGER.exception('Unsupported model: %s', self._model) async def async_turn_off(self): """Turn Mill unit off.""" #device_info = self._device.info() #DEVICE_MODEL = device_info.model if self._model == "zhimi.heater.mc2": self._device.raw_command('set_properties',[{"value":False,"siid":2,"piid":1, "did":DEVICE_ID}]) elif self._model == "zhimi.heater.zb1" or self._model == "zhimi.heater.za2" : self._device.raw_command('set_properties',[{"value":False,"siid":2,"piid":2}]) elif self._model == "zhimi.heater.za1" : self._device.raw_command('set_properties',[{"value":False,"siid":2,"piid":1}]) else: _LOGGER.exception('Unsupported model: %s', self._model) async def async_update(self): """Retrieve latest state.""" self.getAttrData() async def async_set_hvac_mode(self, hvac_mode): """Set operation mode.""" if hvac_mode == HVAC_MODE_HEAT or hvac_mode == HVAC_MODE_COOL: await self.async_turn_on() elif hvac_mode == HVAC_MODE_OFF: await self.async_turn_off() else: _LOGGER.error("Unrecognized operation mode: %s", hvac_mode)
I inserted the code into the climate.py. But HA never did. Here are the logs This error originated from a custom integration.
Logger: custom_components.miheater.climate Source: custom_components/miheater/climate.py:80 Integration: miheater (documentation) First occurred: 1:08:50 PM (1 occurrences) Last logged: 1:08:50 PM
zhimi.heater.za1 2.2.1 esp32 detected
Logger: homeassistant.components.climate Source: custom_components/miheater/climate.py:200 Integration: climate (documentation, issues) First occurred: 1:08:52 PM (1 occurrences) Last logged: 1:08:52 PM
Error while setting up miheater platform for climate Traceback (most recent call last): File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 249, in _async_setup_platform await asyncio.shield(task) File "/usr/local/lib/python3.9/concurrent/futures/thread.py", line 52, in run result = self.fn(*self.args, **self.kwargs) File "/config/custom_components/miheater/climate.py", line 84, in setup_platform miHeater = MiHeater(device, name, model, unique_id, hass) File "/config/custom_components/miheater/climate.py", line 122, in init self.getAttrData() File "/config/custom_components/miheater/climate.py", line 200, in getAttrData data['humidity'] = humidity[0]["value"] KeyError: 'value'
my config: climate:
I guess the problem is in the humidity part. does your heater return humidity in the xiaomi app?
try replacing data['humidity'] = humidity[0]["value"]
with data['humidity'] = 0
That's the thing, my heater does not have any humidity sensors.
maybe this:
@property
def current_humidity(self):
"""Return the current humidity."""
return self._state['humidity']
can be removed completely if you dont use it right? But you had it in the code for when some one uses the zb1 offcourse
Yeah, that one was included by someone to add support for it. If it causes problems, we can remove it.
I created a beta version with your code (1.6.1) if you want to try.
And version 1.6.2 without humidity for za1.
And version 1.6.2 without humidity for za1.
Logger: homeassistant.components.climate Source: custom_components/miheater/climate.py:204 Integration: Климат (documentation, issues) First occurred: 14:12:16 (1 occurrences) Last logged: 14:12:16
Error while setting up miheater platform for climate Traceback (most recent call last): File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 249, in _async_setup_platform await asyncio.shield(task) File "/usr/local/lib/python3.9/concurrent/futures/thread.py", line 52, in run result = self.fn(*self.args, **self.kwargs) File "/config/custom_components/miheater/climate.py", line 84, in setup_platform miHeater = MiHeater(device, name, model, unique_id, hass) File "/config/custom_components/miheater/climate.py", line 122, in init self.getAttrData() File "/config/custom_components/miheater/climate.py", line 204, in getAttrData data['power'] = power[0]["value"] KeyError: 'value'
It seems it's not even getting the Power status from your heater.
This means that these codes are not correct:
power=self._device.raw_command('get_properties', [{"siid":2,"piid":1}])
This is the hard part :p
My JF1 has humidity
From: sygys @.> Sent: Wednesday, September 29, 2021 1:53 PM To: ee02217/homeassistant-mi-heater @.> Cc: droserHA @.>; Mention @.> Subject: Re: [ee02217/homeassistant-mi-heater] Not work on zhimi.heater.za1 (#6)
maybe this:
@property
def current_humidity(self):
"""Return the current humidity."""
return self._state['humidity']
can be removed completely if you dont use it right? But you had it in the code for when some one uses the zb1 offcourse
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/ee02217/homeassistant-mi-heater/issues/6#issuecomment-930066066 , or unsubscribe https://github.com/notifications/unsubscribe-auth/ATKGMY3VEKVYIO4IPJ5NRLTUELVX7ANCNFSM4VICP2NQ . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub .
It seems it's not even getting the Power status from your heater. This means that these codes are not correct:
power=self._device.raw_command('get_properties', [{"siid":2,"piid":1}])
This is the hard part :p
in za1 there is temperature and humidity!!!
thats strange looking at the xiaomi page the siid and piid seems to be the values i put in. I recommend using node red to fire these commands at the heater. that way you get a payload back which tells you what goes wrong. My knowledge isnt good enough to help you further
maybe the za1 also needs this: "did":DEVICE_ID??
One way you can test, is by installing python-miio (https://python-miio.readthedocs.io/en/latest/discovery.html#installation) and trying the commands like this:
miiocli device --ip 192.168.1.XXX --token ZZZZZZZZZZZZZZZZZZZZZZZZ raw_command get_properties '[{"piid":1,"siid":2}]'
This will allow you to validate the necessary values for using in the code :)
just send me climate.py and I will test))))
It's updated on new version. It's a beta release.
It's updated on new version. It's a beta release.
I tested. did not work(((
Logger: custom_components.miheater.climate Source: /config/custom_components/miheater/climate.py:191 Integration: miheater (documentation) First occurred: 12:48:44 PM (3 occurrences) Last logged: 12:48:44 PM
Unsupported model: zhimi.heater.za1 NoneType: None
Logger: homeassistant.components.climate Source: custom_components/miheater/climate.py:193 Integration: Climate (documentation, issues) First occurred: 12:48:44 PM (3 occurrences) Last logged: 12:48:44 PM
Error while setting up miheater platform for climate Traceback (most recent call last): File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 199, in _async_setup_platform await asyncio.shield(task) File "/usr/local/lib/python3.8/concurrent/futures/thread.py", line 57, in run result = self.fn(*self.args, **self.kwargs) File "/config/custom_components/miheater/climate.py", line 80, in setup_platform miHeater = MiHeater(device, name, model, unique_id, hass) File "/config/custom_components/miheater/climate.py", line 116, in init self.getAttrData() File "/config/custom_components/miheater/climate.py", line 193, in getAttrData data['power'] = power[0]["value"] UnboundLocalError: local variable 'power' referenced before assignment