Posted by: @derek-mIn the _init_.py there is the following code which imports data from HA. I have a feeling that HA contains a list of the sensors etc. from which data can be obtained from the various devices, and I believe that I have seen code that checks this list before requesting the data. Could you have a look through the HA files to see if there is such a list, and if so, then send a copy.
I am still of the opinion that data is extracted from a device by requesting it by name, which needs to be in the specified list. When you used Byte1 etc. I believe that you were just naming a variable into which the data was deposited, after it had been extracted.
Quite a lot of the midea_ac_lan files import from HA. The import lines at the top of the files (sorry if I'me teaching GM's to suck eggs) do the importing, sometimes the whole file, sometime part of it (from x import y) and sometimes an alias is added (import verylongname as vln).
I think any imported sensors are probably generic sensors, mainly because of the way you set up midea_ac_lan. To add it, you have to
(a) copy the files into the custom_components directory
(b) probably restart HA, then 'Add Integration' > select Midea AC LAN and then it will take you through a setup routine which first discovers any Midea devices you have and then sets up a default entity (sensor)
(c) you then manually add the entities (sensors) from a drop down list. The key point is that the sensors that appear in that list come from the midea_ac_lan code. When I add
C3Attributes.byte_09: { "type": "sensor", "name": "Byte 09", "device_class": SensorDeviceClass.TEMPERATURE, "unit": TEMP_CELSIUS, "state_class": SensorStateClass.MEASUREMENT },
to midea_devices.py (and the other byte_09 code in other files) then sensor.byte_09 appears in the list of available entities. If I added C3Attributes.flying_pig_air_speed with a name "Flying Pig Air Speed" I would have a sensor.flying_pig_air_speed sensor, and so on.
The code self.byte_09 = (body[data_offset + 9]) in c3/message.py then triggers the association between the data in body[data_offset_09] with the byte_09 entity/sensor. If I had self.flying_pig_air_speed = (body[data_offset + 9]) then I would have the Flying pig's air speed available in HA (only it wouldn't be airborne, given the range of values found in byte_09).
The other thing is I think it highly unlikely HA would maintain a list of specific sensors for anything it might be connected to, far too much like hard work. Instead, the custom compents is expected to tell HA what sensors it can provide, what type the are, and what the units are etc (these again being generic options in HA. I used temperature/measurement for byte_09 because if can handle continuous variables. Other options are things like energy/total increasing (for the cumulative energy consumed/produced), and there are also binary sensor for things that are on/off.
The missing link is still what it is that sets the contents (payload) of the 03/01 and 04/04 messages (and any other messages that may or may not exist.
Looking through the HA core files is very arduous, the HA developers don't like you doing that one bit. The crippled HA OS doesn't have root access, you only get to see a very small number of HA folders and files. The samba network addon has the same limitation. No doubt they think they are protecting us from ourselves. However there are ways round this limitation, eg by connecting over SCP, which gives me ftp like root access, ie I can see copy and do limited things with folders and files, including view them in a text editor, but what I can't do is 'find in files' ie search for text within files. Nor can I run anything, as it's just ftp like access. As there are tens if not hundreds of thousands of files that make up the HA installation, trying to find a midea sensor in that code bloat would be worse than trying to find an argon atom in a haystack.
Midea 14kW (for now...) ASHP heating both building and DHW
I forgot to add the code in the previous post.
from homeassistant.const import ( CONF_NAME, CONF_TOKEN, CONF_HOST, CONF_IP_ADDRESS, CONF_PORT, CONF_PROTOCOL, CONF_DEVICE_ID, CONF_TYPE, CONF_CUSTOMIZE, TEMP_FAHRENHEIT, ATTR_DEVICE_ID, ATTR_ENTITY_ID )
@derek-m - that is the from x import y form of importing. I realised we can view HA files on github (and get the extra tools that provides). The above extract comes from here (<=link). It looks like a sort of templating and/or constants setup to me, that gets used to set up sensors. I couldn't find anything vendor or even heat pump specific. But, if we found and wanted to set up a flow rate data sensor, we would probably use (line 756 et seq):
# Volume Flow Rate units class UnitOfVolumeFlowRate(StrEnum): """Volume flow rate units.""" CUBIC_METERS_PER_HOUR = "m³/h" CUBIC_FEET_PER_MINUTE = "ft³/m"
as the basis for our unit line ("unit": CUBIC_METERS_PER_HOUR).
Midea 14kW (for now...) ASHP heating both building and DHW
Thanks for the response, which appears to close one avenue of investigation. I have attached a spreadsheet detailing the data that I think that the messages contain. It would appear that message type 01 is produced by the main body of C3 messages, whilst the type 04 message I believe is produced by the Notify1 section of code. I also believe that to add additional data to message type 01, it may require code similar to that shown below.
class NewProtocolTags(IntEnum): indoor_humidity = 0x0015 screen_display = 0x0017 breezeless = 0x0018 prompt_tone = 0x001A indirect_wind = 0x0042 fresh_air_1 = 0x0233 fresh_air_2 = 0x004b class MessageNewProtocolQuery(MessageACBase): def __init__(self, device_protocol_version): super().__init__( device_protocol_version=device_protocol_version, message_type=MessageType.query, body_type=0xB1) @property def _body(self): query_params = [ NewProtocolTags.indirect_wind, NewProtocolTags.breezeless, NewProtocolTags.indoor_humidity, NewProtocolTags.screen_display, NewProtocolTags.fresh_air_1, NewProtocolTags.fresh_air_2 ] _body = bytearray([len(query_params)]) for param in query_params: _body.extend([param & 0xFF, param >> 8]) return _body lass MessageNewProtocolSet(MessageACBase): def __init__(self, device_protocol_version): super().__init__( device_protocol_version=device_protocol_version, message_type=MessageType.set, body_type=0xB0) self.indirect_wind = None self.prompt_tone = None self.breezeless = None self.screen_display = None self.fresh_air_1 = None self.fresh_air_2 = None @property def _body(self): pack_count = 0 payload = bytearray([0x00]) if self.breezeless is not None: pack_count += 1 payload.extend( NewProtocolMessageBody.pack( param=NewProtocolTags.breezeless, value=bytearray([0x01 if self.breezeless else 0x00]) )) if self.indirect_wind is not None: pack_count += 1 payload.extend( NewProtocolMessageBody.pack( param=NewProtocolTags.indirect_wind, value=bytearray([0x02 if self.indirect_wind else 0x01]) )) if self.prompt_tone is not None: pack_count += 1 payload.extend( NewProtocolMessageBody.pack( param=NewProtocolTags.prompt_tone, value=bytearray([0x01 if self.prompt_tone else 0x00]) )) if self.screen_display is not None: pack_count += 1 payload.extend( NewProtocolMessageBody.pack( param=NewProtocolTags.screen_display, value=bytearray([0x64 if self.screen_display else 0x00]) )) if self.fresh_air_1 is not None and len(self.fresh_air_1) == 2: pack_count += 1 fresh_air_power = 2 if self.fresh_air_1[0] > 0 else 1 fresh_air_fan_speed = self.fresh_air_1[1] payload.extend( NewProtocolMessageBody.pack( param=NewProtocolTags.fresh_air_1, value=bytearray([ fresh_air_power, fresh_air_fan_speed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]) )) if self.fresh_air_2 is not None and len(self.fresh_air_2) == 2: pack_count += 1 fresh_air_power = 1 if self.fresh_air_2[0] > 0 else 0 fresh_air_fan_speed = self.fresh_air_2[1] payload.extend( NewProtocolMessageBody.pack( param=NewProtocolTags.fresh_air_2, value=bytearray([ fresh_air_power, fresh_air_fan_speed, 0xFF ]) )) payload[0] = pack_count return payload
@derek-m - I think you may have found something important:
class MessageNewProtocolQuery(MessageACBase): def __init__(self, device_protocol_version): super().__init__( device_protocol_version=device_protocol_version, message_type=MessageType.query, body_type=0xB1) @property def _body(self): query_params = [ NewProtocolTags.indirect_wind, NewProtocolTags.breezeless, NewProtocolTags.indoor_humidity, NewProtocolTags.screen_display, NewProtocolTags.fresh_air_1, NewProtocolTags.fresh_air_2 ] _body = bytearray([len(query_params)]) for param in query_params: _body.extend([param & 0xFF, param >> 8]) return _body
That (and indeed much of the rest of the quote) looks very credible as a query message building routine. In the above, for example, near the top we see the message_type and body_type being set, in the rest we see the query parameters set and then added to the body using a for loop.
That's the good news. The not so good news is that code looks very complicated, very tricky to replicate...
Midea 14kW (for now...) ASHP heating both building and DHW
Posted by: @cathoderaySomething is badly broken, and I have no idea what it is. I can't help wondering though if Midea have messed with the protocol again, in keeping with their policy of making sure foreign devils live in interesting times.
One thing I noticed at about this time is that the time is now back to GMT. I have suspected for a while that the Midea Cloud controls the time because every time I change it some while later (perhaps midnight somewhere) it changes back.
The heat pump is very dumb itself and just takes messages and sets its parameters accordingly. Your code needs to be very careful as too many cooks spoils the broth!
I am catching up after the hiatus caused by moderation.
Phil
Posted by: @filipeOne thing I noticed at about this time is that the time is now back to GMT. I have suspected for a while that the Midea Cloud controls the time because every time I change it some while later (perhaps midnight somewhere) it changes back.
I think you are right, my observations however were more that it doesn't know about DST, and so doesn't automatically shift its clock in October and March.
The broken code I think was in fact a red herring, the real reason for loss of first midea_ac_lan and then all HA is that both HA and the Midea controller by default use dynamic IP addressing. It looks as though mine got reassigned for some reason, and so the connections broke. I have now set static IP addresses, and I think the problem is solved. If it stays fixed, I'll write it up properly in the Beginner's Guide thread.
Midea 14kW (for now...) ASHP heating both building and DHW
Posted by: @cathoderay@derek-m - I think you may have found something important:
class MessageNewProtocolQuery(MessageACBase): def __init__(self, device_protocol_version): super().__init__( device_protocol_version=device_protocol_version, message_type=MessageType.query, body_type=0xB1) @property def _body(self): query_params = [ NewProtocolTags.indirect_wind, NewProtocolTags.breezeless, NewProtocolTags.indoor_humidity, NewProtocolTags.screen_display, NewProtocolTags.fresh_air_1, NewProtocolTags.fresh_air_2 ] _body = bytearray([len(query_params)]) for param in query_params: _body.extend([param & 0xFF, param >> 8]) return _bodyThat (and indeed much of the rest of the quote) looks very credible as a query message building routine. In the above, for example, near the top we see the message_type and body_type being set, in the rest we see the query parameters set and then added to the body using a for loop.
That's the good news. The not so good news is that code looks very complicated, very tricky to replicate...
If you would like to send a text copy of the C3 device and message files, I will see if I can modify them to achieve the desired result. I will probably start by adding just one known parameter to ensure that it does actually work. One thing that I am still unsure of is the code shown below. It would appear that different signals/sensors have been allocated a unique code, but I cannot yet find such a list or interpret the meaning of the unique code. Do you have any idea's? I don't think that 0x0015 indicates that the data for indoor humidity is located at byte 15 in the message body since some of the other New Protocol Tags are obviously binary data i.e. True or False, which would not be transmitted using a full byte.
class NewProtocolTags(IntEnum): indoor_humidity = 0x0015 screen_display = 0x0017 breezeless = 0x0018 prompt_tone = 0x001A indirect_wind = 0x0042 fresh_air_1 = 0x0233 fresh_air_2 = 0x004b
Posted by: @derek-mIf you would like to send a text copy of the C3 device and message files
Done (by DM)
Posted by: @derek-mDo you have any idea's?
Might they be arbitrary, then once set, they can subsequently be used? There certainly doesn't seem to be any pattern to them.
From the python docs:
An enumeration:
is a set of symbolic names (members) bound to unique values...
IntEnum
Base class for creating enumerated constants...
Midea 14kW (for now...) ASHP heating both building and DHW
Posted by: @cathoderayPosted by: @derek-mIf you would like to send a text copy of the C3 device and message files
Done (by DM)
Posted by: @derek-mDo you have any idea's?
Might they be arbitrary, then once set, they can subsequently be used? There certainly doesn't seem to be any pattern to them.
From the python docs:
An enumeration:
is a set of symbolic names (members) bound to unique values...
IntEnum
Base class for creating enumerated constants...
It may become clearer later, though it is annoying that the code is poorly documented.
Maybe you could ask the question on GITHUB, since the person who wrote the code will hopefully be able to explain.
Posted by: @derek-mMaybe you could ask the question on GITHUB, since the person who wrote the code will hopefully be able to explain.
I (and a few others with similar questions) have posted questions on Github for both developers but no recent relevant responses at all. Both versions are effectively abandonware, unfortunately.
It has occurred to me they know something they are not supposed to know (eg internal documents), and that is why they are being evasive. I've always found it hard to see how they could write such complicated and esoteric code from scratch.
Midea 14kW (for now...) ASHP heating both building and DHW
Posted by: @cathoderayPosted by: @derek-mMaybe you could ask the question on GITHUB, since the person who wrote the code will hopefully be able to explain.
I (and a few others with similar questions) have posted questions on Github for both developers but no recent relevant responses at all. Both versions are effectively abandonware, unfortunately.
It has occurred to me they know something they are not supposed to know (eg internal documents), and that is why they are being evasive. I've always found it hard to see how they could write such complicated and esoteric code from scratch.
You may well be correct.
I have had a further thought. Rather than just adding new items to the list, maybe they should be appended to the original message body, and possibly create a new body type in the process. I may try this method first, since it will probably be the easier option. This method has been used in AC, which created different body types which could then be selected as the correct response, as in the code below.
@property def body(self): body = bytearray([self._body_type]) + self._body body.append(calculate(body)) return body class MessageACResponse(MessageResponse): def __init__(self, message): super().__init__(message) body = message[self.HEADER_LENGTH: -1] if self._message_type == MessageType.notify2 and self._body_type == 0xA0: self._body = XA0MessageBody(body) elif self._message_type == MessageType.notify1 and self._body_type == 0xA1: self._body = XA1MessageBody(body) elif self._message_type in [MessageType.query, MessageType.set, MessageType.notify2] and \ self._body_type in [0xB0, 0xB1, 0xB5]: self._body = XBXMessageBody(body, self._body_type) elif self._message_type in [MessageType.query, MessageType.set] and self._body_type == 0xC0: self._body = XC0MessageBody(body) elif self._message_type == MessageType.query and self._body_type == 0xC1: self._body = XC1MessageBody(body) self.set_attr()
- 22 Forums
- 2,048 Topics
- 44.6 K Posts
- 72 Online
- 3,274 Members
Join Us!
Trusted Installers
Struggling to find a reliable heat pump installer? A poor installation can lead to inefficiencies and high running costs. We now connect homeowners with top-rated installers who deliver quality work and excellent service.
✅ Verified, trusted & experienced installers
✅ Nationwide coverage expanding
✅ Special offers available
Latest Posts
-
RE: Agile: average import cost vs other tariffs?
@old_scientist We are with SSEN and our G99 application...
By Toodles , 1 hour ago
-
RE: Yes, the "zoning with ASHP" topic again...
@ccap On the subject of TRV’s, when I had the gas boile...
By Toodles , 3 hours ago
-
RE: Battery sizing - How low can you go!
@chandykris We seem to have similarly sized systems and...
By bontwoody , 4 hours ago
-
RE: Renewables & Heat Pumps in the News
@transparent Red Eléctrica will require data with gr...
By Lucia , 5 hours ago
-
Doubling of annual allowance for distribution network s...
By Jeff , 6 hours ago
-
RE: Solar Power Output – Let’s Compare Generation Figures
Yes. Storing the solar generation within the home is gr...
By Transparent , 8 hours ago
-
RE: ASHP Ecodan L9 error - No Heating but Hot Water
@phoenix15, @heacol cover your area… I’d strongly recom...
By Mars , 10 hours ago
-
RE: Warm weather and heat pumps.
@editor Oh nothing right now because $ needed for struc...
By Lucia , 21 hours ago
-
Maybe you could do a video on it please? Ask all the ma...
By Lucia , 21 hours ago
-
@iantelescope - I do appreciate I am becoming something...
By cathodeRay , 24 hours ago
-
RE: Potentially more choice including air to air heat pump grants
@jeff Such documents are far too wordy for my ‘daily re...
By Toodles , 1 day ago
-
RE: Getting the best out of a heat pump - is Homely a possible answer?
@grahaml I cannot agree that it is a small percentage o...
By benson , 2 days ago
-
RE: Commencing on an ASHP Installation Process
In that case treating it as a separate space seems emin...
By JamesPa , 2 days ago
-
RE: Samsung Gen6 16kW tribulations
@emceed, can you please give us an update on your syste...
By Mars , 3 days ago
-
What's the problem you are trying to solve. The answer...
By JamesPa , 5 days ago
-
Good luck. For what it is worth my system was very def...
By JamesPa , 5 days ago
-
RE: Massive Electricity Cost for Running My Air Source Heat Pump
I agree @mark-h The Building Regs are now very readable...
By Transparent , 6 days ago
-
RE: Help me understand my Mitsubishi Ecodan system
@carpenterstation When changing settings in the ser...
By RobS , 6 days ago
-
RE: Ecodan Legionella cycle - immersion heater problem
Thanks for letting us know @clockworks I admire your ...
By Transparent , 7 days ago