Prius Gen2 A/C compressor inverter
-
- Posts: 53
- Joined: Wed Dec 26, 2018 1:38 pm
- Location: Greystones Ireland
- Has thanked: 15 times
- Been thanked: 38 times
Re: Prius Gen2 A/C compressor inverter
Observations:
1) I'd say my A/C pressure switch is gone when I bypass it the A/C start
2) If your hybrid battery is bad the car will not run A/C https://www.mavyn.com/blog/decoding-p0a ... xes-causes
3) I was using an SFH618A Optocoupler to connect the 12V signal to my 5V logical analyser to capture logs. This stops the A/C running.
1) I'd say my A/C pressure switch is gone when I bypass it the A/C start
2) If your hybrid battery is bad the car will not run A/C https://www.mavyn.com/blog/decoding-p0a ... xes-causes
3) I was using an SFH618A Optocoupler to connect the 12V signal to my 5V logical analyser to capture logs. This stops the A/C running.
-
- Posts: 53
- Joined: Wed Dec 26, 2018 1:38 pm
- Location: Greystones Ireland
- Has thanked: 15 times
- Been thanked: 38 times
-
- Posts: 53
- Joined: Wed Dec 26, 2018 1:38 pm
- Location: Greystones Ireland
- Has thanked: 15 times
- Been thanked: 38 times
Re: Prius Gen2 A/C compressor inverter
Hmm, I didn't expect the CLK signal to come from the inverter.
-
- Posts: 53
- Joined: Wed Dec 26, 2018 1:38 pm
- Location: Greystones Ireland
- Has thanked: 15 times
- Been thanked: 38 times
Re: Prius Gen2 A/C compressor inverter
Thank you WOSS for confirming. I'm now trying to figure out how to update the Arduino software from the ES27C thread to use an incoming clk instead of sending the clk.
Re: Prius Gen2 A/C compressor inverter
Have you figured out how to start the air conditioning compressor? What is the communication protocol of the air conditioning compressor?
-
- Posts: 53
- Joined: Wed Dec 26, 2018 1:38 pm
- Location: Greystones Ireland
- Has thanked: 15 times
- Been thanked: 38 times
Re: Prius Gen2 A/C compressor inverter
Making some small progress as mentioned previous in this thread it's some kind of SPI interface.
See script below for Ardunio Naon that can decode and reply to inverter:
Code: Select all
// Pin Definitions
const int clockPin = 13; // SPI Clock Pin (active low)
const int dataInPin = 11; // Data Pin for receiving data
const int dataOutPin = 12; // Data Pin for sending response
const int packetSize = 10; // Number of bytes in a packet
// Timing Definitions
const unsigned long clockCycleTime = 3200; // Clock cycle time in microseconds (3.2ms)
const unsigned long byteReceiveTime = 26000; // Time to receive one byte (26ms)
const unsigned long packetGapTime = 80000; // Time between packets (80ms)
// Fixed Response Data
byte responseData[packetSize] = {0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF};
//byte responseData[packetSize] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A};
// Variables
byte receivedData[packetSize]; // Buffer to store received data
unsigned long lastPacketTime = 0; // Last time a packet was received
bool receivingPacket = false; // Are we currently receiving a packet?
void setup() {
pinMode(clockPin, INPUT); // Set the clock pin as input
pinMode(dataInPin, INPUT); // Set the data input pin as input
pinMode(dataOutPin, OUTPUT); // Set the data output pin as output
Serial.begin(9600); // Start serial communication for debugging
digitalWrite(dataOutPin, LOW); // Initialize data output to low
}
void loop() {
unsigned long currentTime = micros();
// Check for the 80ms gap and the first clock pulse (active low)
if (!receivingPacket && (currentTime - lastPacketTime >= packetGapTime) && digitalRead(clockPin) == LOW) {
// Ready to receive a new packet
receivingPacket = true;
lastPacketTime = currentTime; // Reset the last packet time
receiveAndRespondPacket();
}
}
void receiveAndRespondPacket() {
unsigned long startTime = micros();
for (int byteIndex = 0; byteIndex < packetSize; byteIndex++) {
byte receivedByte = 0;
// Read 8 bits (1 byte) from the data line, synchronized with clock
for (int bitIndex = 0; bitIndex < 8; bitIndex++) {
//waitForClockPulse(); // Wait for the clock to go low (active low)
// Wait for the clock to go low (active low)
while (digitalRead(clockPin) == HIGH) {
// Wait for clock to go low
}
// Send corresponding bit from the response byte
bool responseBit = (responseData[byteIndex] >> (7 - bitIndex)) & 1;
digitalWrite(dataOutPin, responseBit ? HIGH : LOW);
// Wait for half the clock cycle to synchronize bit read
delayMicroseconds(clockCycleTime / 2);
receivedByte <<= 1; // Shift left to make space for the new bit
if (digitalRead(dataInPin) == HIGH) {
receivedByte |= 1; // Set the bit if the data input pin is high
}
// Wait for the clock to complete its cycle
waitForClockReturn();
}
// Store the received byte in the buffer
receivedData[byteIndex] = receivedByte;
// Wait for the remainder of the 26ms per byte, if needed
while (micros() - startTime < byteReceiveTime * (byteIndex + 1)) {
// Waiting until time for the next byte
}
if (byteIndex < (packetSize -1))
{
digitalWrite(dataOutPin, LOW);
}
}
receivingPacket = false;
lastPacketTime = micros(); // Update the last packet time
// Debugging: Print the received packet
Serial.print("Received Packet: ");
for (int i = 0; i < packetSize; i++) {
Serial.print(receivedData[i], HEX);
Serial.print(" ");
}
Serial.println();
}
void waitForClockPulse() {
// Wait for the clock to go low (active low)
while (digitalRead(clockPin) == HIGH) {
// Wait for clock to go low
}
// Wait for half the clock cycle to synchronize bit read
delayMicroseconds(clockCycleTime / 2);
}
void waitForClockReturn() {
// Wait for clock to go high to complete the cycle
while (digitalRead(clockPin) == LOW) {
// Wait for clock to go high
}
}
Output:
20:33:54.002 -> Received Packet: 0 0 0 0 0 0 C 0 0 73
20:33:54.399 -> Received Packet: 0 0 2 0 0 0 18 0 0 E5
20:33:54.798 -> Received Packet: 0 0 2 0 0 0 18 0 0 E5
20:33:55.196 -> Received Packet: 0 0 2 0 0 0 18 0 0 E5
20:33:55.594 -> Received Packet: 0 0 2 0 0 0 18 0 0 E5
20:33:55.992 -> Received Packet: 0 0 2 0 0 0 18 0 0 E5
20:33:56.390 -> Received Packet: 0 0 82 0 0 0 18 0 0 65
20:33:56.788 -> Received Packet: 0 0 82 0 0 0 18 0 0 65
20:33:57.186 -> Received Packet: 0 0 82 0 0 0 18 0 0 65
20:33:57.584 -> Received Packet: 0 0 82 0 0 0 18 0 0 65
20:33:57.982 -> Received Packet: 0 0 82 0 0 0 18 0 0 65
20:33:58.380 -> Received Packet: 0 0 82 0 0 0 18 0 0 65
20:33:58.778 -> Received Packet: 0 0 82 0 0 0 18 0 0 65
20:33:59.176 -> Received Packet: 0 0 82 0 0 0 18 0 0 65
20:33:59.574 -> Received Packet: 0 0 82 0 0 0 18 0 0 65
20:33:59.972 -> Received Packet: 0 0 82 0 0 0 18 0 0 65
20:34:00.371 -> Received Packet: 0 0 82 0 0 0 18 0 0 65
20:34:00.769 -> Received Packet: 0 0 82 0 0 0 18 0 0 65
20:34:01.167 -> Received Packet: 0 0 82 0 0 0 18 0 0 65
20:34:01.531 -> Received Packet: 0 0 82 0 0 0 18 0 0 65
20:34:01.930 -> Received Packet: 0 0 82 0 0 0 18 0 0 65
20:34:02.328 -> Received Packet: 0 0 82 0 0 0 18 0 0 65
20:34:02.726 -> Received Packet: 0 0 82 0 0 0 18 0 0 65
20:34:03.124 -> Received Packet: 0 0 82 0 0 0 18 0 0 65
20:34:03.522 -> Received Packet: 0 0 82 0 0 0 18 0 0 65
20:34:03.920 -> Received Packet: 0 0 82 0 0 0 18 0 0 65
20:34:04.318 -> Received Packet: 0 0 82 0 0 0 18 0 0 65
PulsView file attached
- Attachments
-
- chatgtpv25.sr.gz
- (2.33 KiB) Downloaded 348 times
-
- chatgtpv25.pvs.gz
- (685 Bytes) Downloaded 337 times
-
- Posts: 53
- Joined: Wed Dec 26, 2018 1:38 pm
- Location: Greystones Ireland
- Has thanked: 15 times
- Been thanked: 38 times
Re: Prius Gen2 A/C compressor inverter
Finally managed to capture logs of the A/C turning on for real.
I did this using my 5V logical analyzer with a CD4504B voltage level shifter.
There was some noise, which I filtered out.
Now, I'm trying to figure out the CRC and send back ETI messages using an Arduino Nano.
Sigrok files attached.
Videos how I captured
CD4504B pin connections
1 VCC (12V)
2 AOUT (CLK to 5V logical analyzer)
3 AIN (CLK)
4 BOUT (ETI to 5V logical analyzer)
5 BIN (ETI)
6 COUT (STB to 5V logical analyzer)
7 CIN (STB)
8 VSS GND
9 DOUT (ITE to 5V logical analyzer)
10 DIN (ITE)
11 EOUT
12 EIN
13 SELECT (GND)
14 FIN
15 FOUT
16 VDD (5V)
Decoder settings
I did this using my 5V logical analyzer with a CD4504B voltage level shifter.
There was some noise, which I filtered out.
Now, I'm trying to figure out the CRC and send back ETI messages using an Arduino Nano.
Sigrok files attached.
Videos how I captured
CD4504B pin connections
1 VCC (12V)
2 AOUT (CLK to 5V logical analyzer)
3 AIN (CLK)
4 BOUT (ETI to 5V logical analyzer)
5 BIN (ETI)
6 COUT (STB to 5V logical analyzer)
7 CIN (STB)
8 VSS GND
9 DOUT (ITE to 5V logical analyzer)
10 DIN (ITE)
11 EOUT
12 EIN
13 SELECT (GND)
14 FIN
15 FOUT
16 VDD (5V)
Decoder settings
- Attachments
-
- ac on for real video2 20250201 edited MISO ETI.txt
- (3.32 KiB) Downloaded 321 times
-
- ac on for real with tis video 20250201 edited.zip
- (13.44 KiB) Downloaded 328 times
-
- ac on for real video2 20250201 edited.zip
- (11.92 KiB) Downloaded 311 times
-
- Posts: 1013
- Joined: Fri Apr 26, 2019 5:40 pm
- Has thanked: 388 times
- Been thanked: 257 times
Re: Prius Gen2 A/C compressor inverter

What in the unholy Cthulhu hell of Mom's Spaghetti...
I noped right out of trying to understand it, and skipped right forward to appreciating whatever it is that was done.
-
- Posts: 53
- Joined: Wed Dec 26, 2018 1:38 pm
- Location: Greystones Ireland
- Has thanked: 15 times
- Been thanked: 38 times
Re: Prius Gen2 A/C compressor inverter
Success! It Works! 
We can now control the Gen2 A/C compressor inverter!
Arduino code & logs: GitHub Repository
Also, I figured out the CRC codes using ChatGPT:
Byte 5 = (B1 ≪ 1) ⊕ B2 ⊕ B3 ⊕ B4
Next Steps
Create a wiring diagram in KiCad.
Decode the log: AC on for real - video
- Update the Arduino code to send continuous messages instead of replaying recorded log messages.
- This will allow full control of the inverter.
Update the Wiki with the latest findings.
Start testing with different inverter versions & car models to ensure compatibility.
Potential Uses for the A/C Inverter
Run A/C on Gen2 conversions.
Charging applications: Discussion.
Power three-phase accessories.
Demo Video: YouTube Shorts
Big thank you to xp677 for the work on Denso ES27C AC Compressor control (Toyota/Lexus)
We can now control the Gen2 A/C compressor inverter!
Also, I figured out the CRC codes using ChatGPT:
Byte 5 = (B1 ≪ 1) ⊕ B2 ⊕ B3 ⊕ B4
- Update the Arduino code to send continuous messages instead of replaying recorded log messages.
- This will allow full control of the inverter.
Big thank you to xp677 for the work on Denso ES27C AC Compressor control (Toyota/Lexus)
-
- Posts: 53
- Joined: Wed Dec 26, 2018 1:38 pm
- Location: Greystones Ireland
- Has thanked: 15 times
- Been thanked: 38 times
Re: Prius Gen2 A/C compressor inverter
This is a man in the middle board for toyota prius gen2 HV ECU see https://github.com/hakanrolsson/PriusHVConnectorMattsAwesomeStuff wrote: ↑Sun Feb 09, 2025 1:06 am
What in the unholy Cthulhu hell of Mom's Spaghetti...
I noped right out of trying to understand it, and skipped right forward to appreciating whatever it is that was done.
-
- Posts: 1013
- Joined: Fri Apr 26, 2019 5:40 pm
- Has thanked: 388 times
- Been thanked: 257 times
Re: Prius Gen2 A/C compressor inverter

I have a prius gen 2 air conditioner system, I could presumably hook it up and use it for its intended purpose now. Or, repurpose it as a charger perhaps (though, I do want A/C, but I also have a Gen 3 air con system which has its inverter built into the compressor and just needs PWM input I think).
johu wrote:
Can this be integrated into the existing hardware/software for the Prius Gen 2 board, or is something standalone needed?
-
- Posts: 53
- Joined: Wed Dec 26, 2018 1:38 pm
- Location: Greystones Ireland
- Has thanked: 15 times
- Been thanked: 38 times
Re: Prius Gen2 A/C compressor inverter
https://github.com/hakanrolsson/Prius-G ... verter.pdf
In my opinion, more suited for stm32-car or ZombieVerter.MattsAwesomeStuff wrote: ↑Fri Feb 21, 2025 11:21 pm Can this be integrated into the existing hardware/software for the Prius Gen 2 board, or is something standalone needed?
Done
- johu
- Site Admin
- Posts: 6618
- Joined: Thu Nov 08, 2018 10:52 pm
- Location: Kassel/Germany
- Has thanked: 341 times
- Been thanked: 1484 times
- Contact:
Re: Prius Gen2 A/C compressor inverter
Thanks very much for your work!
To be honest after initial excitement the Gen2 controller became a bit of a shelve warmer so I'm not currently planning a new revision. I agree this would fit better into one of the VCU projects.MattsAwesomeStuff wrote: ↑Fri Feb 21, 2025 11:21 pm Can this be integrated into the existing hardware/software for the Prius Gen 2 board, or is something standalone needed
Support R/D and forum on Patreon: https://patreon.com/openinverter - Subscribe on odysee: https://odysee.com/@openinverter:9
-
- Posts: 1013
- Joined: Fri Apr 26, 2019 5:40 pm
- Has thanked: 388 times
- Been thanked: 257 times
Re: Prius Gen2 A/C compressor inverter
Longer discussion for another day, but, partial solutions with moderate documentation never become a viable choice for an amateur.
People don't need 10 choices, they would be happy with 1 choice that is the easiest to use. Or rather, people will choose the one solution that is most likely to solve their problem for them.
As it turns out, the Gen2 transaxle was kind of anemic without dual motor control, and maybe speed limited too. Without fully using all of the things on board in the inverter as a system, or the One Stop Junkyard trip to get it all at once, I think the lackluster transaxle performance poisoned the cheapness and utility of the rest of the Gen2 stuff, especially the inverter. If you're going to use a Leaf motor, you're going to grab the Leaf stack. If a dual-motor version had been the default, then the transaxle doesn't look so wimpy anymore, and it becomes a more viable option again.
The "judge how much more development to put into it, based on sales of the half-completed development version" isn't that useful of a metric, especially when it's low-end and the major advantage is how well bundled of a solution it could potentially be. Though from a developer standpoint, "Keep putting effort into something not many people have shown enthusiasm for" isn't attractive either. It's entirely possible you dump double the effort into it, and get no additional results. In the end, a crappy metric might be better than no metric, and, there isn't really any way of predicting this except to imagine what people might want if it was done.
I empathize.
-
- Posts: 53
- Joined: Wed Dec 26, 2018 1:38 pm
- Location: Greystones Ireland
- Has thanked: 15 times
- Been thanked: 38 times
Re: Prius Gen2 A/C compressor inverter
OK, so I have a solution that kind of works to control the A/C compressor inverter. I took the messages from the TIS run and the Arduino program and converted it to esp32 that have a Wi-Fi module and made an interface similar to TIS. Roughly mapped messages with RPM (still haven't fully decoded the content in the messages). I will park this development for now. If someone want to pick up the thread, I'll be more than happy to help with development boards etc. The most important objective for me has been achieved that, that the inverter is active and can be turned off, thus hopefully making sure the gates are permanently low to be able to use the inverter for charging without modifications.
Code: Select all
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
// Pin Definitions
const int clockPin = 18; // SPI Clock Pin (active low)
const int dataInPin = 19; // Data Pin for receiving data
const int dataOutPin = 23; // Data Pin for sending response
const int chipSelectPin = 5; // Chip Select Pin
const int packetSize = 10; // Number of bytes in a packet
// Timing Definitions
const unsigned long clockCycleTime = 3200; // Clock cycle time in microseconds (3.2ms)
const unsigned long byteReceiveTime = 26000; // Time to receive one byte (26ms)
const unsigned long packetGapTime = 80000; // Time between packets (80ms)
// Fixed Response Data
byte responseData[packetSize] = {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
int compressorTargetSpeed = 0; // Default target speed
// Wi-Fi Access Point Credentials
const char* ssid = "CompressorControl";
const char* password = "12345678";
// Web Server
AsyncWebServer server(80);
// Variables
byte receivedData[packetSize];
unsigned long lastPacketTime = 0;
bool receivingPacket = false;
void processReceivedData() {
// Modify response based on compressor target speed
if (compressorTargetSpeed == 100) {
byte defaultResponse[packetSize] = {0xFB, 0x3F, 0xFE, 0xFF, 0xC5, 0xFB, 0x3F, 0xFE, 0xFF, 0xC5};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 200) {
byte defaultResponse[packetSize] = {0xDE, 0x3F, 0xFE, 0xFF, 0xE0, 0xDE, 0x3F, 0xFE, 0xFF, 0xE0};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 300) {
byte defaultResponse[packetSize] = {0xF2, 0xDF, 0xFE, 0xFF, 0x2C, 0xF2, 0xDF, 0xFE, 0xFF, 0x2C};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 400) {
byte defaultResponse[packetSize] = {0xE1, 0x5F, 0xFE, 0xFF, 0xBF, 0xE1, 0x5F, 0xFE, 0xFF, 0xBF};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 500) {
byte defaultResponse[packetSize] = {0xD7, 0x5F, 0xFE, 0xFF, 0x99, 0xD7, 0x5F, 0xFE, 0xFF, 0x99};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 600) {
byte defaultResponse[packetSize] = {0xE1, 0x5F, 0xFE, 0xFF, 0xBF, 0xE1, 0x5F, 0xFE, 0xFF, 0xBF};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 700) {
byte defaultResponse[packetSize] = {0xC4, 0x5F, 0xFE, 0xFF, 0x86, 0xC4, 0x5F, 0xFE, 0xFF, 0x86};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 800) {
byte defaultResponse[packetSize] = {0xFD, 0x9F, 0xFE, 0xFF, 0x63, 0xFD, 0x9F, 0xFE, 0xFF, 0x63};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 900) {
byte defaultResponse[packetSize] = {0xEF, 0x1F, 0xFE, 0xFF, 0xF1, 0xEF, 0x1F, 0xFE, 0xFF, 0xF1};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 1000) {
byte defaultResponse[packetSize] = {0xC9, 0x1F, 0xFE, 0xFF, 0xCF, 0xC9, 0x1F, 0xFE, 0xFF, 0xCF};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 1100) {
byte defaultResponse[packetSize] = {0xD3, 0xEF, 0xFE, 0xFF, 0x3D, 0xD3, 0xEF, 0xFE, 0xFF, 0x3D};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 1200) {
byte defaultResponse[packetSize] = {0xE6, 0xEF, 0xFE, 0xFF, 0x04, 0xE6, 0xEF, 0xFE, 0xFF, 0x04};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 1300) {
byte defaultResponse[packetSize] = {0xF9, 0x6F, 0xFE, 0xFF, 0x97, 0xF9, 0x6F, 0xFE, 0xFF, 0x97};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 1400) {
byte defaultResponse[packetSize] = {0xDC, 0x6F, 0xFE, 0xFF, 0xB2, 0xDC, 0x6F, 0xFE, 0xFF, 0xB2};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 1500) {
byte defaultResponse[packetSize] = {0xF0, 0xAF, 0xFE, 0xFF, 0x5E, 0xF0, 0xAF, 0xFE, 0xFF, 0x5E};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 1600) {
byte defaultResponse[packetSize] = {0xD5, 0x2F, 0xFE, 0xFF, 0xFB, 0xD5, 0x2F, 0xFE, 0xFF, 0xFB};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 1700) {
byte defaultResponse[packetSize] = {0xC7, 0xCF, 0xFE, 0xFF, 0x15, 0xC7, 0xCF, 0xFE, 0xFF, 0x15};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 1800) {
byte defaultResponse[packetSize] = {0xFE, 0xCF, 0xFE, 0xFF, 0x30, 0xFE, 0xCF, 0xFE, 0xFF, 0x30};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 1900) {
byte defaultResponse[packetSize] = {0xCA, 0x4F, 0xFE, 0xFF, 0x9C, 0xCA, 0x4F, 0xFE, 0xFF, 0x9C};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 2000) {
byte defaultResponse[packetSize] = {0xF7, 0x8F, 0xFE, 0xFF, 0x79, 0xF7, 0x8F, 0xFE, 0xFF, 0x79};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 2100) {
byte defaultResponse[packetSize] = {0xE4, 0x8F, 0xFE, 0xFF, 0x66, 0xE4, 0x8F, 0xFE, 0xFF, 0x66};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 2200) {
byte defaultResponse[packetSize] = {0xC3, 0x0F, 0xFE, 0xFF, 0xD3, 0xC3, 0x0F, 0xFE, 0xFF, 0xD3};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 2300) {
byte defaultResponse[packetSize] = {0xFA, 0x0F, 0xFE, 0xFF, 0xF4, 0xFA, 0x0F, 0xFE, 0xFF, 0xF4};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 2400) {
byte defaultResponse[packetSize] = {0xE4, 0x8F, 0xFE, 0xFF, 0x66, 0xE4, 0x8F, 0xFE, 0xFF, 0x66};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 2500) {
byte defaultResponse[packetSize] = {0xF7, 0x8F, 0xFE, 0xFF, 0x79, 0xF7, 0x8F, 0xFE, 0xFF, 0x79};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 2600) {
byte defaultResponse[packetSize] = {0xED, 0x4F, 0xFE, 0xFF, 0xAB, 0xED, 0x4F, 0xFE, 0xFF, 0xAB};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 2700) {
byte defaultResponse[packetSize] = {0xD8, 0xCF, 0xFE, 0xFF, 0x0E, 0xD8, 0xCF, 0xFE, 0xFF, 0x0E};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 2800) {
byte defaultResponse[packetSize] = {0xFE, 0xCF, 0xFE, 0xFF, 0x30, 0xFE, 0xCF, 0xFE, 0xFF, 0x30};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 2900) {
byte defaultResponse[packetSize] = {0xE2, 0x2F, 0xFE, 0xFF, 0xC2, 0xE2, 0x2F, 0xFE, 0xFF, 0xC2};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 3000) {
byte defaultResponse[packetSize] = {0xCE, 0xAF, 0xFE, 0xFF, 0x68, 0xCE, 0xAF, 0xFE, 0xFF, 0x68};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 3100) {
byte defaultResponse[packetSize] = {0xDC, 0x6F, 0xFE, 0xFF, 0xB2, 0xDC, 0x6F, 0xFE, 0xFF, 0xB2};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 3200) {
byte defaultResponse[packetSize] = {0xF9, 0x6F, 0xFE, 0xFF, 0x97, 0xF9, 0x6F, 0xFE, 0xFF, 0x97};
memcpy(responseData, defaultResponse, packetSize);
}
else if (compressorTargetSpeed == 3300) {
byte defaultResponse[packetSize] = {0xE6, 0xEF, 0xFE, 0xFF, 0x04, 0xE6, 0xEF, 0xFE, 0xFF, 0x04};
memcpy(responseData, defaultResponse, packetSize);
}
else {
byte defaultResponse[packetSize] = {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
memcpy(responseData, defaultResponse, packetSize);
}
}
void receiveAndRespondPacket() {
unsigned long startTime = micros();
for (int byteIndex = 0; byteIndex < packetSize; byteIndex++) {
byte receivedByte = 0;
for (int bitIndex = 0; bitIndex < 8; bitIndex++) {
while (digitalRead(clockPin) == LOW) { delayMicroseconds(1); }
bool responseBit = (responseData[byteIndex] >> (7 - bitIndex)) & 1;
digitalWrite(dataOutPin, responseBit ? LOW : HIGH);
delayMicroseconds(clockCycleTime / 2);
receivedByte <<= 1;
if (digitalRead(dataInPin) == HIGH) receivedByte |= 1;
while (digitalRead(clockPin) == HIGH) { delayMicroseconds(1); }
}
receivedData[byteIndex] = receivedByte;
while (micros() - startTime < byteReceiveTime * (byteIndex + 1)) { delayMicroseconds(1); }
if (byteIndex < (packetSize - 1)) digitalWrite(dataOutPin, LOW);
}
receivingPacket = false;
lastPacketTime = micros();
Serial.print("Received: ");
for (int i = 0; i < packetSize; i++) {
Serial.printf("%02X ", receivedData[i]);
}
Serial.println();
}
void updateSpeed(int change) {
compressorTargetSpeed += change;
if (compressorTargetSpeed < 0) compressorTargetSpeed = 0;
if (compressorTargetSpeed > 7500) compressorTargetSpeed = 7500;
processReceivedData();
}
void setup() {
Serial.begin(115200);
pinMode(clockPin, INPUT);
pinMode(dataInPin, INPUT);
pinMode(dataOutPin, OUTPUT);
pinMode(chipSelectPin, OUTPUT);
digitalWrite(dataOutPin, LOW);
digitalWrite(chipSelectPin, HIGH);
WiFi.softAP(ssid, password);
Serial.printf("Wi-Fi started. Connect to: %s\n", WiFi.softAPIP().toString().c_str());
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
String html = "<html><head><title>Compressor Control</title>";
html += "<meta name='viewport' content='width=device-width, initial-scale=1'>";
html += "<style>body { font-family: Arial; text-align: center; } ";
html += "button { font-size: 20px; padding: 10px 20px; margin: 10px; } ";
html += "</style></head><body>";
html += "<h2>Compressor Target Speed</h2>";
html += "<h1 id='speed'>" + String(compressorTargetSpeed) + " RPM</h1>";
html += "<a href='/decrease'><button>< Decrease</button></a>";
html += "<a href='/increase'><button>Increase ></button></a>";
html += "<script> setInterval(() => { fetch('/speed').then(res => res.text()).then(data => document.getElementById('speed').innerText = data + ' RPM'); }, 1000); </script>";
html += "</body></html>";
request->send(200, "text/html", html);
});
server.on("/increase", HTTP_GET, [](AsyncWebServerRequest *request) {
updateSpeed(100);
request->redirect("/");
});
server.on("/decrease", HTTP_GET, [](AsyncWebServerRequest *request) {
updateSpeed(-100);
request->redirect("/");
});
server.on("/speed", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send(200, "text/plain", String(compressorTargetSpeed));
});
server.begin();
}
void loop() {
unsigned long currentTime = micros();
if (!receivingPacket && (currentTime - lastPacketTime >= packetGapTime) && digitalRead(clockPin) == HIGH) {
receivingPacket = true;
lastPacketTime = currentTime;
receiveAndRespondPacket();
}
}
- johu
- Site Admin
- Posts: 6618
- Joined: Thu Nov 08, 2018 10:52 pm
- Location: Kassel/Germany
- Has thanked: 341 times
- Been thanked: 1484 times
- Contact:
Re: Prius Gen2 A/C compressor inverter
Great effort, thanks a lot
I didn't think of that aspect. Will you test this?
Support R/D and forum on Patreon: https://patreon.com/openinverter - Subscribe on odysee: https://odysee.com/@openinverter:9