Closed wolfson292 closed 2 months ago
Oh nice. Thanks. I spent a lot of the last 48 hours on this and made a lot of progress. You can see all of my protocol decoding work here. I got lights, temperature, jet pumps and more decoded and working.
I also made progress on the ESP32 integration and got lights and temperature working really well. I how have my Home Assistant automatically change the temperature based on electricity rates and recording the temperature graph. I can switch lights on and off and it's very fast, not much lag.
I still have a few more days to go before it's something others can use. I have to work a bit more to get both Celsius and Fahrenheit modes working well. More importantly, the Spa Connection Kit polls for the data every minute and so, I just listen to that traffic, no need to add more traffic to the RS485 bus if I don't need to. I am coding it so the ESP32 will detect if a Spa Connection Kit device is already present and will not poll, but if it's not present it will do the polling itself.
Are you a Home Assistant user? If so, I would go buy a M5Stack+RS485+Wires right away (it takes a while to deliver and it's cheap). If your not using Home Assistant, let me know what setup your looking to integrate with.
Also, if you have a music module on your Spa or any information on that module, let me know. I would absolutely love to get a traffic capture of the audio device. I want to impersonate it so I can control Home Assistant audio from the spa display,
Any decoding help you can provide is very much appreciated!
@wolfson292 - Just tried your commands and yes, they do work. Just added them to the protocol document. Huge thanks.
FYI for everyone, more progress this morning. I got a lot more features supported and exposed to Home Assistant.
0x02, 0x55 and 0x02, 0x56 have the same handler, but 0x56 includes additional fields. Everything up to the length of 0x55 is the same in 0x56 response.
To tell if the device is in C or F mode, you can check byte 15, bit 6, of the response (1 = C, 0 = F).
@wolfson292 What are C and F modes?
Oh... Celsius or Fahrenheit probably. I can see that when I read the temperature. However, good to know.
Excellent work, ordered the hardware and looking forward to try it out.
I am from Belgium and have a Hotspring Envoy 2017 with an ace saltwater system and I am using home assistant for all the automation
Thanks @npinguin. Hopefully you can help me test and give me feedback.
Today I am working on getting jets that have multiple speeds working nicely in Home Assistant. I also need to add data polling for this ESP-Home component to work for people that don't have the SPA connection kit, but I should get that done in the next few days.
Great work! Following closely with much interest! Just the thing I have been looking to implement for a while now. Parts are on order & hopefully arriving soon.
Thanks @fricker-ben. Nice to hear this. Certainly motivating me to code. I can't wait to hear your feedback.
Thanks to the information provided by @wolfson292. I added the version string as a sensor.
I may have found the water heater wattage value. 3866W in the picture below. I am polling this every minute anyway and so, a good value for HA graphs.
Ok. I added the polling support long with a bunch more things and updated all the documentation. I think this is pretty much a v1.0 at this point, it's probably something most geeks/nerds can use.
Ok, one more feature. The integration will now show when the hot tub is heating in the climate user interface.
@wolfson292 What are C and F modes?
Oh... Celsius or Fahrenheit probably. I can see that when I read the temperature. However, good to know.
I was originally determining this like you were seeing if the temp string ended with F
, but having the status bit seemed cleaner.
The third temperature is the heater outlet temperature. You'll see it spike when the heater turns on.
Your identification of these functions has allowed me to significantly improve my disassembly of the controller firmware, identifying many more global variables in the code for various statuses. Unsure on the legality of publicly sharing the current disassembly, but it's based off a version WR4.04 and DK4.00 hex
file of the firmware for the controller and wireless display that was available on a public website. I was previously doing a MiTM setup on the RS422 interface with the wireless display, but this RS485 interface is far simpler and doesn't impact the ability to use the display itself.
Plan to upload my version of an IQ2020 component shortly to GitHub. Started on it before I found yours.
Hi @wolfson292. To be clear, I do not want to ever see or be exposed to 3rd party code and please don't post any details about other code or binary from any sources here or on any forum. API's and interfaces are ok. I do appreciate the enthusiasm and that you are even capable of doing this, that is absolutely insane! But yes, please keep it legal and respect other's work.
In any case, yes, thanks for the information on exhaust temp. I will add the outlet temperature to my component right away and the C/F bit to the documentation.
I just added the heater outlet temperature to the integration. One more thing to graph. Thanks @wolfson292!
Hi @wolfson292. To be clear, I do not want to ever see or be exposed to 3rd party code and please don't post any details about other code or binary from any sources here or on any forum. API's and interfaces are ok. I do appreciate the enthusiasm and that you are even capable of doing this, that is absolutely insane! But yes, please keep it legal and respect other's work.
In any case, yes, thanks for the information on exhaust temp. I will add the outlet temperature to my component right away and the C/F bit to the documentation.
Completely understand having worked on many commercial reverse engineering projects.
Identified a few more of the data fields from the 0x02, 0x55/0x56 command.
Data[35-38] Heater Total Runtime Seconds
Data[39-42] Jets 1 Total Runtime Seconds
Data[55-58] Jets 2 Total Runtime Seconds
Data[59-61] Jets 3 Total Runtime Seconds
Data[67-70] Lights Total Runtime Seconds
Data[73-76] Lifetime Runtime Seconds
Data[43-46] Lifetime Runtime Seconds (6 minutes higher than previous value, 1.5yrs, for my own Spa)
Data[47-50] Unknown Counter, 30 on my own Spa
Data[63-66] Unknown Seconds Timer, 0 on my own Spa
Data[63-66] Unknown Seconds Timer, 0 on my own Spa
Data[77-80] Unknown Seconds Timer Related to Jets 1, 0 on my own Spa
Data[81-84] Unknown Seconds Timer Related to Jets 2, 0 on my own Spa
My own Spa only has 1 set of Jets, and they only support On/Off, no speeds. This might be related to the lack of data for some counters.
Wow @wolfson292 that is amazing data! I will add these runtime sensors in the next few hours. I am also reassured you know this business.
By the way, if you ever find a command to control light brightness and colors, that would be a fun one. I could add the brightness control on the existing light. I can read the lights brightness (0 to 5) using 0x0256 but can't control it.
Any other tricks we can do we the spa would be great!!
I just added your counters to the C# DataViewer app. I index starting from the start of the packet.
int HeaterTotalRuntime = getIntFromByteArray(data, 40);
int Jets1TotalRuntime = getIntFromByteArray(data, 44);
int LifetimeRuntimeSeconds1 = getIntFromByteArray(data, 48);
int UnknownCounter1 = getIntFromByteArray(data, 52);
int Jets2TotalRuntime = getIntFromByteArray(data, 60);
int Jets3TotalRuntime = getIntFromByteArray(data, 64);
int UnknownCounter2 = getIntFromByteArray(data, 68);
int LightsTotalRuntime = getIntFromByteArray(data, 72);
int LifetimeRuntimeSeconds2 = getIntFromByteArray(data, 78);
int UnknownCounter3 = getIntFromByteArray(data, 82);
int UnknownCounter4 = getIntFromByteArray(data, 86);
These are my own values, very similar to yours.
Done. Total runtime sensors are now included. I just added the ones we know what they indicate. Big thank you to @wolfson292 for this. I also updated the RS485 protocol page.
This is a temperature graph with my electricity time-of-use rules for the last 24h. Looks good. I am only using electricity at the lower cost rates now.
@wolfson292. I just added the protocol decoding to get/set the current time. This time is also at the end of the 0x0256 response.
Get Current Time
--> 01 1F 40 024C
<-- 1F 01 80 024C3431011400D40701
SSMMHHDDMMYYYY
Encoded as:
SS:MM:HH Seconds (0 to 59), Minutes (0 to 59), Hours (0 to 23).
DD:MM:YYYY Days (1 to 31), Month (0 to 11), Year (2 byte Big-Endian).
Set Current Time
--> 01 1F 40 024C2C2B140405E807
<-- 1F 01 80 024C2C2B140405E80701
Same encoding as Get Current Time.
Just for kicks, I added a new "Set Current Time" to the Data Viewer to set the spa time to your computer's clock.
Would it be possible to transform the timers in seconds in yyy/mm/dd hh:mm:ss in home assistant?
@npinguin I will look into that. In general, I want to keep the sensor as seconds since this allows Home Assistant to perform computations on the results. I could return a string in HH:MM:SS format, but then you can't add/subtract the value easily. One way to change the format is to use a Home Assistant template sensor. This is a generic example below, but when I get a chance, I will see if it works.
sensor:
- platform: template
sensors:
time_in_hh_mm_ss:
friendly_name: "Time in HH:MM:SS"
value_template: >
{% set seconds = states('input_number.your_input_seconds') | int %}
{% set hours = seconds // 3600 %}
{% set minutes = (seconds % 3600) // 60 %}
{% set secs = seconds % 60 %}
{{ '%02d:%02d:%02d' | format(hours, minutes, secs) }}
@npinguin I just added a new document with Home Assistant Sensor Templates. This allows you to change the seconds into any format you like. I provide a full example to show the following:
Hope that helps.
More data on my hot tub power usages over 2 days. Temperature is automatically adjusted. Where I live the prices are approximately:
So this makes a huge difference if I can heat only during off-peak. It's also good for the grid and the environment. I also per-warm the tub by 1 degree F ahead of mid-peak starting at 7am. On weekends it's all off-peak and this system is not used. I wrote up a full blog on this here. I expect to be saving over 330$ a year with this integration.
I just found, documented and added support for the power on counter. Goes up by one each time the hot tub is started.
I just fixed the problem with controlling jets that have a low/high settings. Works great now.
Just installed it, so far so good. Filling up the tub to see if the pumps work etc.
just noticed that power on counter is not visible for me. Tried a new install but did not see the sensor same for some other sensors like the version. Do I need to force something to get a true new install?
Good catch @npinguin . I just updated the configuration yaml file on the main page to add the power_on_counter
value in the sensor
section. That should work now.
Let let us know how it goes.
I received a private email from someone trying to use the RS485MAX module. They can send commands but not receive any. I think the module looks like this:
I just updated the code to support flow_control_pin
in the iq2020
section of the configuration yaml.
iq2020:
uart_id: SpaConnection
flow_control_pin: GPIO0
port: 1234
If you use this specific board, I think you need to set flow_control_pin
to the DE
GPIO pin. However, I will need confirmation that it work, I don't have this setup. I also added a new section in the Devices Document for this setup.
Filled up the tub and all is working perfectly!
Absolutely great work, very happy with this.
how did you get the software version from the spa?
Thanks @npinguin for reporting back. If you can, please let me know what your software version and spa model are. I will keep a running list of tested versions and models. Also, do you happen to have any of the extra modules? Music/ACE/Freshwater?
For the version, I used the following command given by @wolfson292 above.
--> 01 1F 40 0100
<-- 1F 01 80 01005752342E30346465316345303032444B342E303006
Thanks @npinguin for reporting back. If you can, please let me know what your software version and spa model are. I will keep a running list of tested versions and models. Also, do you happen to have any of the extra modules? Music/ACE/Freshwater?
For the version, I used the following command given by @wolfson292 above.
--> 01 1F 40 0100 <-- 1F 01 80 01005752342E30346465316345303032444B342E303006
It is a Hotspring Envoy 2017 with an ace system.
Regarding the command to get the software version, how can I execute it and display it in home assistant? Is it possible to add it as a sensor ?
Thanks! I am a dummy, I forgot to add the version
sensor to the yaml on the front page. I just added it. It looks like this.
text_sensor:
- platform: iq2020
versionstr:
name: Version
For the ACE system, if you ever want added support for it, follow the debugging guide and send over a traffic dump.
No don’t see it, is also not listed in the yaml?
I just added it at the end of the yaml on the main page. Add it and let me know if it works.
Top, just added it and confirms that my firmware is old i guess
Wow. That is super impressive.
anyone experience with firmware upgrades of the tub and what it could bring ? If it ain't broken do not upgrade is the typical recommendation. But i like keeping things up to date
@npinguin - Yes, getting the firmware change log for different versions would be great. I wonder if dealers have that.
@wolfson292 - I sent all 64k possible commands to the IQ2020 from 0x1F and looked for responses. I made the following table and if you have any guesses as to what some of the unknown commands are, please let me know. Thanks!
0100 - Get version string
0109 - Change temperature
0241 - Unknown (02413C001E0000)
024C - Unknown (024C1B0C110300E80701)
0255 - Get status short
0256 - Get status long
0B02 - Jets 1 & Lights on/off - (0B028F)
0B03 - Jets 2 on/off - (0B038E)
0B04 - Jets 3? on/off - (0B0400)
0B07 - Jets 4? on/off - (0B0700)
0B1C - Summer Timer
0B1D - Spa Lock
0B1E - Temperature Lock
0B1F - Clean Cycle
0B20 - Unknown (0B2001)
0B27 - Unknown (0B278C)
1702 - Lights on/off
1705 - Read lights status
1900 - Unknown (190015)
1901 - Unknown Periodic Polling (190100190000000B0004010000)
1D07 - Unknown Periodic Polling (1D07FFFF)
1E02 - Freshwater Salt System - Set Power / Start Test
1E03 - Get FreshWater Salt Module Data
Just published YouTube videos on this integration. Same video with two different edits.
I just put in more updates. When changing settings, the ESP32 will auto-retry a command 3 times at 1/5 second interval. This is needed since there is a tiny chance that two commands would collide on the bus or there is an error and the IQ2020 controller did not get the command.
Also, I added a new sensor with the salt system power level (0 is off and 10 is max power). Only useful if you have this system. I could also remotely change the setting, I am not sure what Home Assistant control I could use for it.
Lastly, if anyone has this document... that would be super useful.
Finally home after a week away. All plugged in & working nicely on my Hot Spring Sovereign! Is there a way to set & view the current temperature in 0.5°C increments?
@fricker-ben - Yes, Fahrenheit is set in 1.0F increments and Celsius in 0.5C increments. I have tested Fahrenheit a lot more than Celsius. You need to change some _f_
to _c_
in the ESPHome device config. In the view below, hit +/- and it should change by 0.5. If it does not, let me know, I will work to fix.
I have changed the f to c, but when pushing the plus/minus button it's going in 1°C increments. Also the temp display only shows to 0 decimal places. The heater outlet temp displays to 0.1°C resolution.
Ok. I will do some testing and fixing on this later today. This is an essential feature of this integration.
@fricker-ben I see the problem, working on it.
I have been testing the new version with the salt water, unfortunately it is not reusing the ace system interfaces which I was hoping it would. Would be great to have the ace system integrated, let me know what you need
I've been working extensively on reverse engineering the IQ2020 firmware from a hex file found online, and have identified the RS485 address (0x1F) of their internet gateway and some of the functions. Followed you on Twitter, and happy to collaborate.
Commands from address 0x1F to IQ2020 at 0x01 have 2 bytes to identify the command, and optional additional bytes. I've identified the following so far.
Get Versions 0x01 0x00
Get/Set Timestamps 0x02 0x4C Seconds ... if Seconds >60, don't set, just return values
Get lots of data 0x02 0x55