Skip to content
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

Some assistance on decoding #20

Open
zizebra opened this issue Aug 30, 2024 · 17 comments
Open

Some assistance on decoding #20

zizebra opened this issue Aug 30, 2024 · 17 comments

Comments

@zizebra
Copy link

zizebra commented Aug 30, 2024

Hi Nic,

Iam hoping you might be able to help me on my case. My heatpump is completely different from yours but appears to be running a variant software which is is most likely the same. I am trying to decode the data which i got and hopefully be able to update the code you wrote to fit my scenario. I uploaded the code you wrote on for gathering timestamps on to my ESP and I picked up that the following is different, the bits are inverted, on the right is my output from from HT,

image

I have not successfully updated your code to work on my case.

@sle118
Copy link

sle118 commented Aug 31, 2024

I'm seeing differences on my Hayward unit as well, and I've adapted the code to make it a full fledged ESPHome component so I can monitor packets and detect some patterns.

For one, the state that the temp prog packet describes here just doesn't work for me. It may be caused by the fact that my model is a "post 2017" and could be running a different firmware that doesn't quite follow the same standard. It is a PC1001 on a HP55TR, though.

For the record, I managed to find a service manual that describes several parameters for my unit, and I'm hoping that knowing the value of each parameter will help me gain a better understanding of the protocol.

For the idea interested, it is here:
https://www.climasoft.ro/cs-content/cs-docs/19222-1619529079.pdf

Perhaps you could share some pictures of your unit and PCB?

@zizebra
Copy link
Author

zizebra commented Aug 31, 2024

Thank you. As I mentioned, my setup is neither a Hayward nor a PC1001 controller; they are entirely different. However, mine uses a 3-pin connector with 12V, GND, and an A pin at 5V. I assumed this was RS485, with the A 5V pin handling communication. My heat pump and controller are similar to another model that uses NICs code and works perfectly. Mine is just slightly different, but as noted, the bit logic seems opposite to NICs, and the terminating bits are double what NIC had. I’m waiting for a logic analyzer to confirm this. In the meantime, I tried to make the necessary changes to the code but was unsuccessful. I’m still learning. I’ve added a few println statements to help me step through the logic, which seems to help. With some assistance, I might just succeed.

@zizebra
Copy link
Author

zizebra commented Aug 31, 2024

Screenshot_2024-08-31-09-40-37-923_com google android apps docs-edit

@zizebra
Copy link
Author

zizebra commented Aug 31, 2024

#20 (comment)
IMG_20240831_095150
117

@sle118
Copy link

sle118 commented Aug 31, 2024

. I’ve added a few println statements to help me step through the logic, which seems to help. With some assistance, I might just succeed.

The first thing to do is to wait for the logic analyzer at least to get a good grasp of the protocol. Alternatively, you could use an Arduino to dump pulses so they can be opened in a tool like pulse view. Without this info, then trying to adapt this sketch is going to be really challenging.

If, however, you think that the data structure (header command, data and checksum for packet length of 12 or 9 bytes) is the same, then you could definitely dump some data with this sketch.

When you are confident about the data format, you could fork this project and post your code for review or help there.

@zizebra
Copy link
Author

zizebra commented Sep 1, 2024

Thank you. While I wait for logic analyzer I will try dumping pulses with Arduino

@sle118
Copy link

sle118 commented Sep 2, 2024

I created a simple protocol decoder script for PulseView. If you find that the dump is similar to the Hayward system, I could share it with you. I wouldn't be surprised that the board in use in the hardware products are made by a third party. I did find a product by the company Phnix that looks very much the same as my Hayward controller

@zizebra
Copy link
Author

zizebra commented Sep 2, 2024

Please share. I am sure I could use it.

@zizebra
Copy link
Author

zizebra commented Sep 2, 2024

Looks like I made progress, I used the arduino code on this chat . I noted that i can see my in and out temp values. But it looks like the checksum in this code is failing, the function trameisvalid is failing, but at i do see something that makes sense. i decided to just printout the values of trame even if they fail the check.

Send Trame, size 12 : dd2c3009131500002f4d030c05
Send Trame, size 12 : d20f372d070da0ec0223053d05
Send Trame, size 12 : dd2c3009121500002f4d030b05
Send Trame, size 12 : d20f372d070da0ec0223053d05
Send Trame, size 12 : dd2c3009121400002f4d030a05
Send Trame, size 12 : d20f372d070da0ec0223053d05
Send Trame, size 12 : dd2c3009121400002f4d030a05
Send Trame, size 12 : d20f372d070da0ec0223053d05
Send Trame, size 12 : dd2c3009121400002f4d030a05
Send Trame, size 12 : d20f372d070da0ec0223053d05

@zizebra
Copy link
Author

zizebra commented Sep 2, 2024

I have confirmed that messages are 104 bits (13 bytes), with message prefix D2 / DD every 3 seconds. DD is denotes the measured values. D2 is the set values. I have not been able to check or confirm controller keypad messages. Any time I press the button, the script generates buffer overflow and prints a string of FFs. Not sure how to get the values for this one. It was suggested that keypad pad messages bits are all inverted. Just not sure how to update the code to test for this and print before raising the buffer overflow.

@sle118
Copy link

sle118 commented Sep 3, 2024

Your best bet is to wait for the logic analyzer. Not sure if your season is getting closer to an end, but I hope you get a chance to capture some data soon. This is definitely the best way to reverse engineer, since you will not be experiencing crashes.

Also, once you have some data, there are interesting open source software options that are really good for decoding unknown protocols

@njanik
Copy link
Owner

njanik commented Sep 3, 2024

@sle118 could you give us some name of software ? I'm currious

@sle118
Copy link

sle118 commented Sep 3, 2024

I was thinking about universal radio hacker (urh), as it is really good at pinpointing changes in packets and at building analysis (I used it with SDR data) but there are manipulations to perform so pulses from a logic analyzer can be used with the tool. I'll see if I can do a bit of fiddling with that; I already have a python script that converts your captures to a simulated ASK modulation, thanks to the help of chatGPT to expedite quick POC, but this is as far as I went last night.

FYI, I have properly extracted the data from the clock frames, and I've made some changes to the code so that I dump changes to bits and values when changes are found. Also, I found some extra temperature sensors: ambient air, coil temperature, etc.

@sle118
Copy link

sle118 commented Sep 3, 2024

also @njanik, here is the "TEMP_OUT" frame as I know it

typedef struct {
  union {
    struct {
      uint8_t decimal : 1;
      uint8_t integer : 5;
      uint8_t unknown_1 : 1;
      uint8_t unknown_2 : 1;
    };
    uint8_t raw;
  };
} __attribute__((packed)) temperature_t;


typedef struct {
  hp_mode_t mode;  // Mode structure at data[2]
  temperature_t set_point_1;
  temperature_t set_point_2; 
  bits_details_t reserved_2;
  bits_details_t reserved_3;
  bits_details_t reserved_4;
  bits_details_t reserved_5;
  bits_details_t reserved_6;
  bits_details_t reserved_7;
} __attribute__((packed)) tempprog_t;

in your original analysis, data[4] had the set point temperature. I suspect that this is because your heat pump was running in "heat" mode. Mine has been setup as "Auto" mode from the factory and so what I am observing is that data[4] never changes for me and is always higher than data[3] (e.g. data[4] is 27 degrees for example and data[4] is 21 degrees). The way I understand this:

Heat mode: single set point in data[4]
Auto Mode: data[3] is the "low" temperature that will trigger the heater, and data[4] is the high temperature that will trigger the system to cool the water.

I am going to navigate the users settings (as found in the technical manual from PHNIX, which I suspect is the manufacturer of these hayward controllers) and see what comes out of it.

I also found several temperature readings from the TEMP_OUT packet:

typedef struct {
  bits_details_t reserved_1;
  bits_details_t reserved_2;
  temperature_t temperature;  // Temperature byte at data[4]
  temperature_t temperature_2;
  temperature_t temperature_3;
  bits_details_t reserved_5;
  temperature_t temperature_4;
  bits_details_t reserved_7;
  bits_details_t reserved_8;
} __attribute__((packed)) tempout_t;

and so far I suspect that they are as follow:

  • temperature : data[4] matches your analysis, temperature going out of the heat pump
  • temperature_2: coil temperature
  • temperature_3: air temperature at exit of fan

This needs to be confirmed, of course.

oh also, here's the clock frame

typedef struct {
  uint8_t reserved1;   // Reserved or ID byte (00)
  uint8_t reserved2;   // Reserved or ID byte (00)
  uint8_t year;        // Year or identifier byte (14)
  uint8_t month;       // Month (07)
  uint8_t day;         // Day (1F)
  uint8_t hour;        // Hour (17)
  uint8_t minute;      // Minute (2C)
  uint8_t reserved3;
  uint8_t reserved4;
} __attribute__((packed)) clock_time_t;

note that the year/month/day is irrelevant since there's no way to set these from the controller/keypad. Days seem to be incrementing overnight, though, so the clock could still be measuring days from power on.

Now this is the overall frame format


typedef struct {
  union {
    uint8_t data[frame_data_length];  // Raw data array
    struct {
      uint8_t frame_type;  // Common field: frame type
      uint8_t reserved;
      union {
        tempout_t tempout;
        tempin_t tempin;
        tempprog_t tempprog;
        clock_time_t clock;  // New clock packet structure
      };
      uint8_t checksum;  // Checksum byte at data[11]
    };
  };
} __attribute__((packed)) hp_packetdata_t;

of course this doesn't apply to frames with length 9, which are still elusive to me. Also, I am storing bits orders as "reversed" from your sketch and only reverse them when transmitting. This makes analysis easier. For example, temperatures have their least significant bit set for half degrees instead of being the most significant bit. And the packets types header values look like this for me :


constexpr uint8_t FRAME_TYPE_TEMP_IN = 0xD1;    // B 11010001 (njanik bit mask: 10001011)
constexpr uint8_t FRAME_TYPE_TEMP_OUT = 0xD2;   // B 01001011 (njanik bit mask: 11010010)
constexpr uint8_t FRAME_TYPE_PROG_TEMP = 0x81;  // B 10000001 (njanik bit mask: 10000001)
constexpr uint8_t FRAME_TYPE_CLOCK = 0xCF;  // Clock

If you are interested to see the work in progress, I could push my current WIP to my fork. Yesterday I was fine tuning the code to suppress duplicate frames and also to print changes when detected.

@sle118
Copy link

sle118 commented Sep 4, 2024

ah, yes and also I think I understand the frames with a length of 9. They seem to be "continuation frames". e.g. temp_out would be one frame of 12 and one frame of 9, for a total of (excluding header and checksum) 19 bytes or so. Interesting as it might provide some extra insight on the embarked sensors. For example, there's a flow meter, which is something that I'm really interested in, especially during fall when leaves restrict the flow of water. I think we can quantify that, since the controller uses the data to protect the equipment

@sle118
Copy link

sle118 commented Sep 6, 2024

@njanik fyi, someone seems to have found a good technical document on the protocol.

https://community.symcon.de/t/midas-waermepumpe-auslesen/53451/3

The link I could find was
https://cdn.contentspeed.ro/pimromstal.websales.ro/cs-content/cs-docs/products/81pch028manualtehnicintrorig_15762_10_1614391324.pdf

However it is going nowhere so I've contacted the original poster to see if the file exists somewhere

@sle118
Copy link

sle118 commented Oct 31, 2024

I just pushed the most stable code to my repository, most likely the last one until next summer as my heat pump was deactivated for a while, developing with a mock backend (not yet cleaned up, so not yet published). A lot of parameters were identified and implemented at this point.
https://github.com/sle118/hayward_pool_heater

Here are some screenshots of the esphome climate component, extended for our heat pump
image
image
image

I will resume reverse-engineering the protocol next year when I open my pool again. There's already a lot of the frame payload implemented and little remaining, aside from state messages and exception conditions. Amongst others, I plan on unplugging sensors one by one to trigger exceptions and capture them, but this isn't something I'll do in the short term.

As usual, anyone wanting to help is welcome and this includes sending a faulting PCB.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants