-
Notifications
You must be signed in to change notification settings - Fork 608
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New device: Moes IR Thermostat (AC Controller) #1755
Conversation
e990718
to
666495d
Compare
0b1130f
to
f1f3453
Compare
posting here the result from "Query Things Data Model" for reference. {
"result": {
"model": {
"modelId": "00000492z1",
"services": [
{
"actions": [],
"code": "",
"description": "",
"events": [],
"name": "默认服务",
"properties": [
{
"abilityId": 1,
"accessMode": "rw",
"code": "infared_switch",
"description": "",
"extensions": {
"iconName": "icon-power",
"attribute": "2"
},
"name": "红外开关",
"typeSpec": {
"type": "bool",
"typeDefaultValue": false
}
},
{
"abilityId": 2,
"accessMode": "ro",
"code": "temp_current",
"description": "",
"extensions": {
"iconName": "icon-dp_c",
"attribute": "2",
"trigger": "direct"
},
"name": "当前温度",
"typeSpec": {
"max": 600,
"min": 0,
"scale": 1,
"step": 1,
"type": "value",
"typeDefaultValue": 0,
"unit": "℃"
}
},
{
"abilityId": 3,
"accessMode": "rw",
"code": "target_temp",
"description": "APP界面能接受的范围是16到30",
"extensions": {
"iconName": "icon-dp_c",
"trigger": "direct"
},
"name": "目标温度",
"typeSpec": {
"max": 30,
"min": 16,
"scale": 0,
"step": 1,
"type": "value",
"typeDefaultValue": 16,
"unit": "℃"
}
},
{
"abilityId": 4,
"accessMode": "rw",
"code": "mode",
"description": "",
"extensions": {
"iconName": "icon-dp_mode"
},
"name": "工作模式",
"typeSpec": {
"range": [
"cold",
"warm",
"auto",
"air",
"dehumidify"
],
"type": "enum",
"typeDefaultValue": "cold"
}
},
{
"abilityId": 5,
"accessMode": "rw",
"code": "fan_level",
"description": "",
"extensions": {
"iconName": "icon-FanSpeed"
},
"name": "风速",
"typeSpec": {
"range": [
"auto",
"low",
"middle",
"high"
],
"type": "enum",
"typeDefaultValue": "auto"
}
},
{
"abilityId": 6,
"accessMode": "ro",
"code": "fault",
"description": "",
"extensions": {
"iconName": "icon-baojing"
},
"name": "故障告警",
"typeSpec": {
"label": [
"serious_fault",
"sensor_fault"
],
"maxlen": 2,
"type": "bitmap",
"typeDefaultValue": 0
}
},
{
"abilityId": 7,
"accessMode": "rw",
"code": "filter_reset",
"description": "",
"extensions": {
"iconName": "icon-dp_loop"
},
"name": "滤网复位",
"typeSpec": {
"type": "bool",
"typeDefaultValue": false
}
},
{
"abilityId": 8,
"accessMode": "ro",
"code": "filter_life",
"description": "",
"extensions": {
"iconName": "icon-dp_time2"
},
"name": "滤网寿命",
"typeSpec": {
"max": 720,
"min": 0,
"scale": 0,
"step": 1,
"type": "value",
"typeDefaultValue": 0,
"unit": "h"
}
},
{
"abilityId": 9,
"accessMode": "rw",
"code": "upper_temp",
"description": "APP界面能操作控制的范围是16到30",
"extensions": {
"iconName": "icon-dp_temp"
},
"name": "设置温度上限",
"typeSpec": {
"max": 30,
"min": 16,
"scale": 0,
"step": 1,
"type": "value",
"typeDefaultValue": 16,
"unit": "℃"
}
},
{
"abilityId": 10,
"accessMode": "rw",
"code": "lower_temp",
"description": "APP界面能操作控制的范围是16到30",
"extensions": {
"iconName": "icon-dp_temp"
},
"name": "设置温度下限",
"typeSpec": {
"max": 30,
"min": 16,
"scale": 0,
"step": 1,
"type": "value",
"typeDefaultValue": 16,
"unit": "℃"
}
},
{
"abilityId": 11,
"accessMode": "rw",
"code": "temp_unit_convert",
"description": "",
"extensions": {
"iconName": "icon-dp_mode"
},
"name": "温标切换",
"typeSpec": {
"range": [
"c",
"f"
],
"type": "enum",
"typeDefaultValue": "c"
}
},
{
"abilityId": 12,
"accessMode": "ro",
"code": "humidity_current",
"description": "",
"extensions": {
"iconName": "icon-shidu",
"attribute": "2",
"trigger": "direct"
},
"name": "当前湿度",
"typeSpec": {
"max": 100,
"min": 0,
"scale": 0,
"step": 1,
"type": "value",
"typeDefaultValue": 0,
"unit": "%"
}
},
{
"abilityId": 15,
"accessMode": "rw",
"code": "work_type",
"description": "",
"extensions": {
"iconName": "icon-dp_mode"
},
"name": "工作类型",
"typeSpec": {
"range": [
"scene_1",
"scene_2",
"scene_3"
],
"type": "enum",
"typeDefaultValue": "scene_1"
}
},
{
"abilityId": 16,
"accessMode": "rw",
"code": "status",
"description": "",
"extensions": {
"iconName": "icon-zhuangtai"
},
"name": " 码库状态",
"typeSpec": {
"range": [
"done",
"run",
"idle"
],
"type": "enum",
"typeDefaultValue": "done"
}
},
{
"abilityId": 18,
"accessMode": "ro",
"code": "runtime",
"description": "",
"extensions": {
"iconName": "icon-dp_time3"
},
"name": "运行时间",
"typeSpec": {
"max": 999999,
"min": 0,
"scale": 0,
"step": 1,
"type": "value",
"typeDefaultValue": 0,
"unit": "h"
}
},
{
"abilityId": 19,
"accessMode": "rw",
"code": "internet_disc_switch",
"description": "",
"extensions": {
"iconName": "icon-dp_mode"
},
"name": "断联开关",
"typeSpec": {
"type": "bool",
"typeDefaultValue": false
}
},
{
"abilityId": 20,
"accessMode": "rw",
"code": "runtime_total_reset",
"description": "",
"extensions": {
"iconName": "icon-dp_loop"
},
"name": "复位累计工作时间",
"typeSpec": {
"type": "bool",
"typeDefaultValue": false
}
},
{
"abilityId": 201,
"accessMode": "rw",
"code": "ir_send",
"description": "",
"extensions": {
"iconName": "icon-icon-test11",
"attribute": "2048"
},
"name": "红外控制下发",
"typeSpec": {
"maxlen": 3072,
"type": "string",
"typeDefaultValue": ""
}
},
{
"abilityId": 202,
"accessMode": "ro",
"code": "ir_study_code",
"description": "",
"extensions": {
"iconName": "icon-shangsheng",
"attribute": "2048"
},
"name": "红外学习值上报",
"typeSpec": {
"maxlen": 128,
"type": "raw"
}
}
]
}
]
}
}
} |
I think this is a compatible/same device as ir_moes_heatpump.yaml. Some of the previously unknown dps you have gotten the documentation for, as well as others that did not show up. It seems strange that it does not send the IR commands automatically, but your docs also have the ir_send and ir_learn dps, so we can add a remote entity to the existing config. The previous report noted that the climate controller dps were only working with the sub device after setting up the remote model, but you appear to have listed the product id of the main IR device, this may affect the IR sending, as it is not tied to a model if you don't use the sub device. Probably some dps need to be set as optional if your device is not being detected as ir_moes_heatpump already. |
PR #1755 contains detailed info on a Moes IR Thermostat (AC Controller) that appears compatible (possibly the very same device). This allows some of the previously unknown dps to be identified, and some to be exposed as secondary entities, including the raw remote controller so the device can be used to control additional devices.
Modified ir_moes_remote with the additional detail above. |
The device does have a dps for sending IR commands, id 201 (ir_send), but looking at the logs on Tuya cloud it seems to be encrypted: {"control":"send_ir","ver":"3","head":"010ece0000000000040014003e00ab00ca","delay":300,"devid":"50:8b:b9:56:40:65","v_devid":"eb0dc7e67bf3fa1c989jsh","key_num":1,"key1":{"key":"M0_T19_S2","data":"02$$0030B24D5FA030CF@%","data_type":0,"relearn":false}} So, not so easy to deal as the API via cloud. For what I could learn on a quick research, sending ir command via DPS requires specific IR codes which can vary depending on the AC model, while the Cloud API allows sending standard commands like turning on/off, set temp to a specific value etc. Regarding the secondary device, by using Query Things Data Model I get a different set of attributes, but when pooling that secondary device localy using tinytuya, it is just reporting the same DPS as the main device, also it doesn't seem to respond to any attempt to set DPS. Here is the result of Query Things Data Model for the secondary device: {
"result": {
"model": {
"modelId": "000000f3vv",
"services": [
{
"actions": [],
"code": "",
"description": "",
"events": [],
"name": "默认服务",
"properties": [
{
"abilityId": 1,
"accessMode": "wr",
"code": "control",
"description": "",
"name": "控制命令",
"typeSpec": {
"type": "enum",
"range": [
"send_ir",
"study",
"study_exit",
"study_key"
]
}
},
{
"abilityId": 2,
"accessMode": "ro",
"code": "study_code",
"description": "",
"name": "学习编码",
"typeSpec": {
"type": "raw",
"maxlen": 128
}
},
{
"abilityId": 3,
"accessMode": "rw",
"code": "ir_code",
"description": "",
"name": "红外编码",
"typeSpec": {
"type": "string",
"maxlen": 255
}
},
{
"abilityId": 4,
"accessMode": "rw",
"code": "key_code",
"description": "",
"name": "码库按键参数",
"typeSpec": {
"type": "string",
"maxlen": 255
}
},
{
"abilityId": 5,
"accessMode": "rw",
"code": "key_code2",
"description": "",
"name": "码库按键参数2",
"typeSpec": {
"type": "string",
"maxlen": 255
}
},
{
"abilityId": 6,
"accessMode": "rw",
"code": "key_code3",
"description": "",
"name": "码库按键参数3",
"typeSpec": {
"type": "string",
"maxlen": 255
}
},
{
"abilityId": 7,
"accessMode": "rw",
"code": "key_study",
"description": "",
"name": "来自学习参数下发",
"typeSpec": {
"type": "raw",
"maxlen": 128
}
},
{
"abilityId": 8,
"accessMode": "rw",
"code": "key_study2",
"description": "",
"name": "来自学习参数下发2",
"typeSpec": {
"type": "raw",
"maxlen": 128
}
},
{
"abilityId": 9,
"accessMode": "rw",
"code": "key_study3",
"description": "",
"name": "来自学习参数下发3",
"typeSpec": {
"type": "raw",
"maxlen": 128
}
},
{
"abilityId": 10,
"accessMode": "wr",
"code": "delay_time",
"description": "",
"name": "红外码发送延时",
"typeSpec": {
"type": "value",
"max": 65535,
"min": 0,
"scale": 1,
"step": 1,
"unit": "ms"
}
},
{
"abilityId": 11,
"accessMode": "wr",
"code": "key_code4",
"description": "",
"name": "新按键参数",
"typeSpec": {
"type": "string",
"maxlen": 255
}
},
{
"abilityId": 12,
"accessMode": "wr",
"code": "key_study4",
"description": "",
"name": "新学习参数",
"typeSpec": {
"type": "raw",
"maxlen": 128
}
},
{
"abilityId": 13,
"accessMode": "rw",
"code": "type",
"description": "",
"name": "码库标识",
"typeSpec": {
"type": "value",
"max": 255,
"min": 0,
"scale": 1,
"step": 1,
"unit": ""
}
},
{
"abilityId": 101,
"accessMode": "wr",
"code": "switch_power",
"description": "",
"name": "开关",
"typeSpec": {
"type": "bool"
}
},
{
"abilityId": 102,
"accessMode": "rw",
"code": "mode",
"description": "",
"name": "模式",
"typeSpec": {
"type": "enum",
"range": [
"0",
"1",
"2",
"3",
"4"
]
}
},
{
"abilityId": 103,
"accessMode": "wr",
"code": "temperature",
"description": "",
"name": "温度",
"typeSpec": {
"type": "value",
"max": 40,
"min": 10,
"scale": 0,
"step": 1,
"unit": ""
}
},
{
"abilityId": 104,
"accessMode": "rw",
"code": "fan",
"description": "",
"name": "风量",
"typeSpec": {
"type": "enum",
"range": [
"0",
"1",
"2",
"3"
]
}
},
{
"abilityId": 105,
"accessMode": "wr",
"code": "swing",
"description": "",
"name": "摆风",
"typeSpec": {
"type": "bool"
}
},
{
"abilityId": 201,
"accessMode": "rw",
"code": "ir_send",
"description": "",
"name": "红外控制下发",
"typeSpec": {
"type": "string",
"maxlen": 3072
}
},
{
"abilityId": 202,
"accessMode": "rw",
"code": "ir_study_code",
"description": "",
"name": "红外学习值上报",
"typeSpec": {
"type": "raw",
"maxlen": 128
}
}
]
}
]
}
}
} |
@make-all Yes, thats how the device works. Setting the dps directly (i.e. Temperature, fan mode etc) will not trigger a ir command. But you can use ir_send DPS to send a command and the related DPS in the device wil be updated automatically. After tinkering with it a bit more I foun a way to succesfuly send IR commands. I found a pattern by watching Tuya cloud > debug device and was able to test IR command using tinytuya, and it works.
How could it be done? I noticed there is a remote.py , So I guess any code to add support for these IR commands would go there? Here is an example of code that works: import tinytuya
import json
# Connect to Device
d = tinytuya.OutletDevice(
dev_id='MAIN_DEVICE_ID',
address='DEVICE_IP_ADDRESS',
local_key='your_key_here',
version=3.3)
# power on with mode cold at 22 C
command = {"control":"send_ir","ver":"3","head":"010ece0000000000040014003e00ab00ca","delay":300,"devid":"MAC_ADDRESS_OF_DEVICE","v_devid":"[[REPLACE_WITH_SUB_DEVICE_ID]]","key_num":1,"key1":{"key":"M0_T22_S0","data":"02$$0030B24DBF40708F@%","data_type":0,"relearn":'false'}}
# power on
# command = {"head":"010ece0000000000040014003e00ab00ca","key1":{"data":"02$$0030B24DBF40D02F@%","data_type":0,"key":"power_on"},"devid":"","key2":{"data":"02$$0030B24D9F6010EF@%","data_type":0,"key":"M0_T18_S1"},"ver":"3","delay":300,"control":"send_ir","v_devid":"[[REPLACE_WITH_SUB_DEVICE_ID]]","key_num":2}
# power off
# command = {"head":"010ece0000000000040014003e00ab00ca","key1":{"data":"02$$0030B24D7B84E01F@%","data_type":0,"key":"power_off"},"devid":"","ver":"3","delay":300,"control":"send_ir","v_devid":"[[REPLACE_WITH_SUB_DEVICE_ID]]","key_num":1}
# Sending the IR command:
payload = d.generate_payload(tinytuya.CONTROL, {"201": json.dumps(command)})
d.send(payload) |
The config has been modified already to implement the ir.send and ir.learn services. If you first learn a command using the ir.learn service, you can then send it by name. Otherwise you can send a single base64 encoded ir string that is the head and data above combined. |
@make-all Thanks for clarifying! Are they supposed to show up as services in Home assistant? Do you mind explaining how I can use them? |
They are services under the remote entity. |
@fabianoarruda Did you manage to get your device working, I'm still real novice with Home Assistant and can't seem to figure out how to link the Card in the dashboard to the remote send command I don't suppose you could help? |
@phoenixmarines Unfortunately No. It doesn't work. The only thing I managed to do so far, was to create a custom python script on HA to send remote commands to the device using Tuya Cloud, via tinytuya. I expose commands as services in HA and can use them on automations. For example, I created a But I haven't figured out yet how to integrate this with the Climate Card. So, this is how it works on tuya-local currently: The Climate card will display all the information correctly from the device, but interacting with the card will only cause the Tuya App and LCD display of the IR thermostat to be updated. No actual IR commands are sent to the AC. So, in my understanding the integration should not try to update the DPs directly (ie. target temp, Fan speed, etc), but the other way around: It should send the IR command, then the device will update the DPs automatically. Additionally, there is another related discussion here on tinytuya, in which I'm trying to figure out how to send the commands locally, instead of via Cloud. |
@fabianoarruda Thank you for sharing your research. Did you make any further progress? I have a similar device (a newer color display variant) and am willing to help. |
@technotiger Not yet, unfortunately. Do you mind sharing more details about your device? |
@fabianoarruda This is the device (just a random listing out of many): There is a possible workaround for your problem. You can create a template climate device. It can combine the working bits and pieces that you have got working so far into an integrated climate device. I have created some climate devices using a combination of sensors and IR blasters and it works perfectly. Check it out. |
Thank you very much @technotiger. I think the climate template you mentioned is exactly what I needed. I'll try using it for now. But in the long run I'm still researching on how to run the commands locally. |
You are welcome @fabianoarruda. I am also using template climate for now. I noticed that the device has good alexa integration with temperature and mode controls (any missing modes can be run as scenes by alexa by first creating tap-and-run automations in the smartlife app). I am using alexa text commands (via alexa media player integration) instead of python scripts. This could be a simpler approach since we are relying on cloud anyway. I looked into your post where you are trying to figure out the codes for local control. My device uses the same format as yours with the codes being differently encoded. I am trying to figure it out, but it seems that the code part is encrypted/obfuscated very differently across devices. In the meanwhile, wouldn't it work, at-least for a particular device, if we simply record the code for each command and then replay it locally? If so, we can later create a solution which uses cloud once to record all codes for a particular device and then uses it locally ever after. |
@technotiger Yeah, I thought about that too. The problem is, the way the Cloud API works it will always send 3 variables per command: Mode, temperature and fan speed. Example: key So, I need to send via Cloud, watch Tuya developer console and record local command for each of these keys. I don't see an easy way to automate all that :/ |
@technotiger Do you mind sharing your configuration for |
@fabianoarruda It is a bit tricky to get it to work correctly. I have used local_tuya to pull the needed values from my device as sensors. You need to create the scripts to set the mode and temperature. The scripts would have to handle the cases when the changes are made from the touch buttons, cloud delays, and possible loops due to cloud and local changes. I am also using an input_text helper to store the last known mode using an automation which ignores the unavailable and unknown states (because the device apparently has a weak wifi module). I plan to do the same for temperature. Here is the configuration for the template climate.
|
Thank you again @technotiger, this is very helpful. I made it work, but I ended up using this forked version since the original version had some bugs, and it was not being maintained. For me it was not showing the fan speed controller even after I configured the
Can you give mote details? I having some of these issues already 😅 Other than that, it works pretty well. Here is my current config by the way: climate:
- platform: climate_template
name: Ar Sala
unique_id: ar_sala
hvac_modes:
- "auto"
- "dry"
- "off"
- "cool"
- "heat"
- "fan_only"
fan_modes:
- "auto"
- "low"
- "medium"
- "high"
min_temp: 17
max_temp: 30
hvac_mode_template: "{{ states('climate.ar_condicionado_sala') }}"
fan_mode_template: "{{ state_attr('climate.ar_condicionado_sala', 'fan_mode') }}"
target_temperature_template: "{{ state_attr('climate.ar_condicionado_sala', 'temperature') }}"
# get current temp.
current_temperature_template: "{{ states('sensor.ar_condicionado_sala_temperature') }}"
# get current humidity.
current_humidity_template: "{{ states('sensor.ar_condicionado_sala_humidity') }}"
set_hvac_mode:
- service: midea_remote.send_keys
data:
mode: "{{ states('climate.ar_sala') }}"
temp: "{{ state_attr('climate.ar_sala', 'temperature') }}"
wind: "{{ state_attr('climate.ar_sala', 'fan_mode') }}"
set_fan_mode:
- service: midea_remote.send_keys
data:
mode: "{{ states('climate.ar_sala') }}"
temp: "{{ state_attr('climate.ar_sala', 'temperature') }}"
wind: "{{ state_attr('climate.ar_sala', 'fan_mode') }}"
set_temperature:
- service: midea_remote.send_keys
data:
mode: "{{ states('climate.ar_sala') }}"
temp: "{{ state_attr('climate.ar_sala', 'temperature') }}"
wind: "{{ state_attr('climate.ar_sala', 'fan_mode') }}" |
If state changes locally from the device, ignore it to prevent loop. Adding a few seconds delay during which the mode script cannot be invoked again also helps. Ignoring unavailable state helps. I am thinking of a hybrid approach wherein the most frequently used settings(say 10) are recorded from cloud logs and then used locally. The rest can continue to go through the cloud. I have not yet used any python scripts in HA. Are you using AppDaemon or pyscript? |
@technotiger Thanks again.
I was able to fix this by comparing the current values with the requested ones, if nothing changed, ignore the command. But I'm curious to see how you did yours, if you don't mind sharing your code.
Yes, I'm tinkering with this right now, that's an interesting idea.
I'm using pyscript. Here is my code: import tinytuya
import json
FAN_MODES = {
'low': 1,
'medium': 2,
'high': 3,
'auto': 0
}
HVAC_MODES = {
'cool': 0,
'heat': 1,
'auto': 2,
'fan_only': 3,
'dry': 4
}
c = task.executor(tinytuya.Cloud, apiRegion="us",
apiKey="<api_key>",
apiSecret="<api_secret>")
device_id = '<tuya_device_id>'
remote_id = '<remote_id>' # This is usually the secondary device you'll see in Tuya Cloud, after you have configured your AC model
# This is used for automations
@service('midea_remote.power_off')
def power_off():
post_data = {
"power": 0
}
task.executor(c.cloudrequest, '/v2.0/infrareds/' + device_id + '/air-conditioners/' + remote_id + '/scenes/command', post=post_data )
# This is the method I'm currently using with the climate template
@service('midea_remote.send_keys')
def send_keys(mode='cool', temp=23, wind='auto'):
current_mode = climate.ar_condicionado_sala
current_temp = climate.ar_condicionado_sala.temperature
current_wind = climate.ar_condicionado_sala.fan_mode
if not (mode == current_mode and temp == current_temp and wind == current_wind):
post_data = {}
if mode == 'off':
post_data = { "power": 0 }
else:
post_data = {
"power": 1, # This parameter is always required. If not sent, Tuya API will complain
"mode": HVAC_MODES[mode],
"temp": temp,
"wind": FAN_MODES[wind]
}
task.executor(c.cloudrequest, '/v2.0/infrareds/' + device_id + '/air-conditioners/' + remote_id + '/scenes/command', post=post_data )
|
Have you seen this script which appears to convert the codes from Broadcom into ones that would work with Tuya. It may be a quicker way to get the codes to use on your device. Unfortunately I'm not very good at scripting so haven't worked it out yet. https://gist.github.com/svyatogor/7839d00303998a9fa37eb48494dd680f |
Here is the current version of my mode change script. The temperature script has similar checks. EDIT: Removed the code. Don't do it, the result is unreliable. I highly recommend using local control as described in my other comment. |
TinyTuya has a Cloud.getdevicelog() function that can pull the developer console logs for you. Though I suspect once you get a few keys you can just see which bits are changing and thus only need a few keys to figure the protocol out. |
After spending like an hour reverse engineering the examples you posted, I got the bright idea of searching "midea remote protocol" and what do you know, it's already documented at https://github.com/sheinz/esp-midea-ir/blob/master/midea-ir.c#L30 🤣 Should be trivial to just build your own IR codes with that. |
PR make-all#1755 contains detailed info on a Moes IR Thermostat (AC Controller) that appears compatible (possibly the very same device). This allows some of the previously unknown dps to be identified, and some to be exposed as secondary entities, including the raw remote controller so the device can be used to control additional devices.
After getting sufficiently irritated by the cloud method, I finally converted my setup to fully local using (1)tinytuya based python script to send the IR/control codes locally (thanks @fabianoarruda), (2)template-climate to create the climate device in HA, and (3)local tuya for reading the DPs from the device. |
Do you mind posting some of them? If they're the same ones LG has used in the past they're pretty easy to decode. |
Sure. Here you go. Let me know if you figure it out. M0_T16_S3 through M0_T30_S3
M1_T16_S3 through M1_T30_S3
|
@technotiger can you please help with more info on how you Setup the tinytuya scripts to work with the template-climate. I need to setup a site with 100 heat pumps. Most are Fujitsus and Daikins so hoping I can reuse the codes between units. |
@technotiger That appears to be the standard 28-bit format. Sometimes the decoding can get mangled and result in that mess. If you can post the |
I used pyscipt which exposes the python functions to HA. You can find my template-climate code above, which has remained almost the same. Template climate calls HA scripts to set temp and mode, the scripts call the python functions.
head: 020ed800000000000700100014001500380026009a013c |
Well, I finished brute forcing it right before I noticed you posted the
As you can see the key is now just My decoder isn't pretty but it gets the job done: from tinytuya.Contrib import IRRemoteControlDevice
head = '020ed800000000000700100014001500380026009a013c'
codelist = {
'M0': (
'01*&#%$0003C0%$0007FC%$0006F8%$000100%$000280%#%$000100%#^',
'01*&#%$0003C0%$0007FC%$0005F0%$000280%$000280%#%#%$000100^',
'01*&#%$0003C0%$0007FC%$0005F0%#%$000100%$000280%#%#%#%#^',
'01*&#%$0003C0%$0007FC%$0004E0%$0003C0%$0006F8^',
'01*&#%$0003C0%$0007FC%$0004E0%$000100%$000100%$0005F0%#^',
'01*&#%$0003C0%$0007FC%$0004E0%#%$000280%$0004E0%$000100^',
'01*&#%$0003C0%$0007FC%$0004E0%#%#%$000100%$0004E0%#%#^',
'01*&#%$0003C0%$0007FC%$0003C0%$0004E0%$0003C0%$000280^',
'01*&#%$0003C0%$0007FC%$0003C0%$000280%$000100%$0003C0%$000100%#^',
'01*&#%$0003C0%$0007FC%$0003C0%$000100%$000280%$0003C0%#%$000100^',
'01*&#%$0003C0%$0007FC%$0003C0%$000100%#%$000100%$0003C0%#%#%#^',
'01*&#%$0003C0%$0007FC%$0003C0%#%$0003C0%$000280%$0003C0^',
'01*&#%$0003C0%$0007FC%$0003C0%#%$000100%$000100%$000280%$000280%#^',
'01*&#%$0003C0%$0007FC%$0003C0%#%#%$000280%$000280%$000100%$000100^',
'01*&#%$0003C0%$0007FC%$0003C0%#%#%#%$000100%$000280%$000100%#%#^',
),
'M1': (
'01*&#%$0003C0%$0007FC%#%$0005F0%$000100%$0005F0%#^',
'01*&#%$0003C0%$0007FC%#%$0004E0%$000280%$0004E0%$000100^',
'01*&#%$0003C0%$0007FC%#%$0004E0%#%$000100%$0004E0%#%#^',
'01*&#%$0003C0%$0007FC%#%$0003C0%$0003C0%$0003C0%$000280^',
'01*&#%$0003C0%$0007FC%#%$0003C0%$000100%$000100%$0003C0%$000100%#^',
'01*&#%$0003C0%$0007FC%#%$0003C0%#%$000280%$0003C0%#%$000100^',
'01*&#%$0003C0%$0007FC%#%$0003C0%#%#%$000100%$0003C0%#%#%#^',
'01*&#%$0003C0%$0007FC%#%$000280%$0004E0%$000280%$0003C0^',
'01*&#%$0003C0%$0007FC%#%$000280%$000280%$000100%$000280%$000280%#^',
'01*&#%$0003C0%$0007FC%#%$000280%$000100%$000280%$000280%$000100%$000100^',
'01*&#%$0003C0%$0007FC%#%$000280%$000100%#%$000100%$000280%$000100%#%#^',
'01*&#%$0003C0%$0007FC%#%$000280%#%$0003C0%$000280%#%$000280^',
'01*&#%$0003C0%$0007FC%#%$000280%#%$000100%$000100%$000280%#%$000100%#^',
'01*&#%$0003C0%$0007FC%#%$000280%#%#%$000280%$000280%#%#%$000100^',
'01*&#%$0003C0%$0007FC%#%$000280%#%#%#%$000100%$000280%#%#%#%#^',
)
}
for k in codelist:
print(k)
for c in codelist[k]:
pulses = IRRemoteControlDevice.head_key_to_pulses( head, c )
new_head_key = IRRemoteControlDevice.pulses_to_head_key( pulses, fudge=0.1, freq=38 )
result = full_result = int( new_head_key[1][8:15], 16 )
#print( ' %s -> %x' % (c, result) )
crc = result & 0x0F
result >>= 4
fan = result & 0x0F
result >>= 4
temp = result & 0x0F
result >>= 4
cmd_mode = result & 0xFF
mode = result & 0x07
#result >>= 4
cmd = result & 0xF8
result >>= 8
header1 = result & 0x0F
result >>= 4
header2 = result & 0x0F
result >>= 4
want_crc = (fan + temp + (cmd_mode & 0x0F) + (cmd_mode >> 4) + header1 + header2) & 0x0F
crc_good = 'good' if want_crc == crc else 'bad'
#print(' %s = %x' % (c, full_result) )
print( ' %s == %x == command %d mode %d temp %d fan %d [crc %s!]' % (c, full_result, cmd, mode, temp+15, fan, crc_good) )
new_head_key = IRRemoteControlDevice.pulses_to_head_key(pulses)
print( ' cleaned up head:', new_head_key[0], 'key:', new_head_key[1] ) I found a few other codes posted at https://raw.githubusercontent.com/nokru/lg-ac-lirc/master/encoded_values.txt and some of the commands decoded at https://forum.arduino.cc/t/solved-lg-air-conditioning-codes/80846/7 . |
Can you please provide an example of the PyScript to control locally. When you say you had to hard code each string how does this work. I'm guessing the HA Climate Template calls a different HA Script based on the options you choose then that HA Script is linked to the corresponding PyScript but I'm not really sure if you need a separate PyScript for every option or is their a simpler way to do this with Variables. |
@uzlonewolf @slnnz The python function can take variables.
The HA script can pass the variables to python.
|
This is my attempt to add compatibility for Moes IR Thermostat - It is a IR controller specific to Air conditioners with built in temperature and humidity sensors. There is also a variant wihtout the LCD screen, which I believe should work the same, but I only have the LCD Screen variant, so not able to confirm.
Details about the device: https://moeshouse.com/products/wifi-ir-thermostat-with-ac-remote-and-sensor?variant=40016596303953
Now, I was able to add the device successfully and it read all attributes correctly, and it is able to set the AC functions - It will update the Tuya device status correctly, example if you change target temperature to 20 C, it will get reflected on the device screen and even in the app... The only problem is, changing the properties via DPS locally will not trigger the IR commands, So it will not set the actual AC temperature.
I have figured out how to send the IR commands via tinytuya using the Cloud integration, but I don't know yet how to bind these commands to the climate device, so when you attempt to change the device on HA, it should trigger the IR command.
Here is an example of code that triggers the IR command correcty so The AC will get the command, and the Tuya device screen will also reflect the change (and it will propagate to HA):
Any help to figure out how to bind these 2 things together is really appreciated.