HeatpumpIR library + sensors example to send IR commands to heatpumps

This commit is contained in:
ToniA
2015-09-29 20:21:42 +03:00
parent 1b8c87704c
commit c9ffef8da3
42 changed files with 4004 additions and 0 deletions
@@ -0,0 +1,204 @@
// HeatpumpIR libraries
#include <FujitsuHeatpumpIR.h>
#include <PanasonicCKPHeatpumpIR.h>
#include <PanasonicHeatpumpIR.h>
#include <CarrierHeatpumpIR.h>
#include <MideaHeatpumpIR.h>
#include <MitsubishiHeatpumpIR.h>
#include <SamsungHeatpumpIR.h>
// Timer library, https://github.com/ToniA/Timer
#include <Timer.h>
// MySensors libraries
#include <MySensor.h>
#include <SPI.h>
// This MySensors node has three childs, with ID's 1, 2 & 3
#define CHILD_1 1
#define CHILD_2 2
#define CHILD_3 3
// MySensors definitions
MySensor gw;
MyMessage irMsg(CHILD_1, V_IR_RECEIVE);
// Domoticz does not yet properly support the S_IR sensor type
MyMessage textMsg(CHILD_2, V_TEXT);
MyMessage sendMsg(CHILD_3, V_LIGHT);
// Array with all supported heatpump models
HeatpumpIR *heatpumpIR[] = { new PanasonicCKPHeatpumpIR(), // 0, keep this if you don't remove the timer for cancelling Panasonic CKP messages
new PanasonicDKEHeatpumpIR(), // 1
new PanasonicJKEHeatpumpIR(), // 2
new PanasonicNKEHeatpumpIR(), // 3
new CarrierHeatpumpIR(), // 4
new MideaHeatpumpIR(), // 5
new FujitsuHeatpumpIR(), // 6
new MitsubishiFDHeatpumpIR(), // 7
new MitsubishiFEHeatpumpIR(), // 8
new SamsungHeatpumpIR() // 9
};
// IR led on PWM output-capable digital pin 3
IRSender irSender(3);
// Timer for sending Panasonic CKP series timer cancellation commands
Timer timer;
int8_t panasonicCKPTimer = 0;
// Number of supported models
byte models = 0;
void setup()
{
Serial.begin(115200);
delay(1000);
Serial.println(F("HeatpumpIR sensor starting up..."));
models = sizeof(heatpumpIR) / sizeof(HeatpumpIR*);
Serial.print(F("Number of supported models: ")); Serial.println(models);
// Auto-assign the node ID, do not forward messages
gw.begin(incomingMessage, AUTO, false);
// Send the sketch version information to the gateway and Controller
gw.sendSketchInfo("Heatpump Sensor", "1.0");
// Register a sensors to the MySensors Gateway
gw.present(CHILD_1, S_IR, "IR sender");
// For Domoticz
gw.present(CHILD_2, S_INFO, "IR data");
gw.present(CHILD_3, S_LIGHT, "IR send");
// The TEXT sensor is not created in Domoticz before data is sent
gw.send(textMsg.setSensor(CHILD_2).set("00000000"));
}
void loop()
{
gw.process();
timer.update();
}
// Handle incoming messages from the MySensors Gateway
void incomingMessage(const MyMessage &message) {
const char *irData;
long irCommand;
// V_IR type message
if (message.type==V_IR_SEND) {
Serial.println(F("Received IR send command..."));
irData = message.getString();
Serial.print(F("Code: 0x"));
Serial.println(irData);
sendHeatpumpIRCommand(irData);
}
// Domoticz
else if (message.type==V_LIGHT) {
// When the button is pressed on Domoticz, request the value of the TEXT sensor
Serial.println(F("Requesting IR code from Domoticz..."));
gw.request(CHILD_2, V_TEXT, 0);
} else if (message.type==V_TEXT) {
// TEXT sensor value is received as a result of the previous step
Serial.println(F("IR code received from Domoticz..."));
Serial.print(F("Code: 0x"));
irData = message.getString();
Serial.println(irData);
sendHeatpumpIRCommand(irData);
// Set the Domoticz switch back to 'OFF' state
gw.send(sendMsg.setSensor(CHILD_3).set(0));
}
}
// Decode the IR command and send the IR command to the heatpump
void sendHeatpumpIRCommand(const char *irCommandString) {
// irCommandString is an 8-digit hex digit
long irCommand = 0;
int sscanfStatus = sscanf(irCommandString, "%lx", &irCommand);
if (sscanfStatus == 1) {
Serial.print(F("IR code conversion OK: 0x"));
Serial.println(irCommand, HEX);
} else {
Serial.println(F("Failed to convert IR hex code to number"));
}
/*
The heatpump command is packed into a 32-bit hex number, see
libraries\HeatpumpIR\HeatpumpIR.h for the constants
12345678
3 MODEL
4 POWER
5 OPERATING MODE
6 FAN SPEED
78 TEMPERATURE IN HEX
00213416 (as an example of a valid code)
2 = PanasonicJKE
1 = Power ON
3 = COOL
4 = FAN 4
16 = Temperature 22 degrees (0x16 = 22)
*/
byte model = (irCommand & 0x00F00000) >> 20;
byte power = (irCommand & 0x00010000) >> 16;
byte mode = (irCommand & 0x0000F000) >> 12;
byte fan = (irCommand & 0x00000F00) >> 8;
byte temp = (irCommand & 0x000000FF);
prog_char* buf;
Serial.print(F("Model: "));
buf = (prog_char*)heatpumpIR[model]->model();
// 'model' is a PROGMEM pointer, so need to write a byte at a time
while (char modelChar = pgm_read_byte(buf++))
{
Serial.print(modelChar);
}
Serial.println();
Serial.print(F("Model #: ")); Serial.println(model);
Serial.print(F("Power: ")); Serial.println(power);
Serial.print(F("Mode: ")); Serial.println(mode);
Serial.print(F("Fan: ")); Serial.println(fan);
Serial.print(F("Temp: ")); Serial.println(temp);
// Heatpump models start from 0, i.e. model number is always less than the number of different models
if (model < models) {
// This is a supported model
// Cancel the timer on Panasonic CKP heatpump
if (model == 0) {
Serial.println(F("Cancelling timer on Panasonic CKP heatpump..."));
timer.stop(panasonicCKPTimer);
}
Serial.println(F("All OK - sending IR command to heatpump..."));
heatpumpIR[model]->send(irSender, power, mode, fan, temp, VDIR_UP, HDIR_AUTO);
if (model == 0) {
Serial.println(F("Scheduling timer cancellation on Panasonic CKP heatpump..."));
panasonicCKPTimer = timer.after(120000, panasonicCancelTimer, (void *)NULL); // Called after 2 minutes
}
}
}
// Cancel the timer on the Panasonic CKP heatpump
void panasonicCancelTimer(void *context)
{
PanasonicCKPHeatpumpIR *panasonicCKPHeatpumpIR = new PanasonicCKPHeatpumpIR();
panasonicCKPHeatpumpIR->sendPanasonicCKPCancelTimer(irSender);
Serial.println(F("The TIMER led should now be OFF"));
}
@@ -0,0 +1,73 @@
# MySensors example
This example shows how HeatpumpIR could be integrated with the MySensors sensor network. As this sensor sends infrared signals,
the natural sensor type is 'S_IR'. The heatpump/air conditioner signals are really long, so the signals need to be encoded somehow.
In this example the idea is to encode just this information, using 24 bits of data
* model code (see the index of the array heatpumpIR in the code)
* power state (for the rest, see the HeatpumpIR.h file for the constants)
* operating mode
* fan speed
* temperature (the temperature is directly the temperature in HEX)
```
An example:
00213416 (as an example of a valid code)
2 = PanasonicJKE
1 = Power ON
3 = COOL
4 = FAN 4
16 = Temperature 22 degrees (0x16 = 22)
```
This sketch creates three sensors:
* S_IR
* S_INFO
* S_LIGHT
The S_INFO and S_LIGHT sensors are for Domoticz, as it does not currently (as of V2.3093) support infrared code sending through the S_IR sensor type.
## Sending the code
### MYSController
* Select the IR sensor on the 'Heatpump Sensor 1.0' node
* Select 'IR_SEND' as the subtype
* Enter for example '00213416' as the payload
### Domoticz
As Domoticz does not really support sending IR code yet, the workaround is to use two sensors. When the node is connected, Domoticz should find two new devices
* A 'Lighting 2 / AC' type sensor with name 'IR send'
* A 'General / Text' type sensor with name 'Unknown' and Data '00000000'
To send a command, first add the sensors. Then update the data of the text sensor to contain the IR code to be sent, and then flip the switch to trigger the sending.
The data can be updated through the JSON REST API, or through the Lua event scripts.
REST API example (assuming that the idx of the text sensor is 105 and the switch is 104, and Domoticz is at 192.168.0.4:8080):
```
http://192.168.0.4:8080/json.htm?type=command&param=udevice&idx=105&nvalue=0&svalue=00213416
http://192.168.0.4:8080/json.htm?type=command&param=switchlight&idx=104&switchcmd=On
```
Lua example:
* Seems that the text sensor can't be updated through the commandArray...
* So now when a device called 'trigger' changes, the text sensor value is first updated to '00213416', and then the IR signal is sent
```
commandArray = {}
for key, value in pairs(devicechanged) do
if (key == 'trigger') then
print("Heatpump script")
commandArray['OpenURL']='http://192.168.0.4:8080/json.htm?type=command&param=udevice&idx=105&nvalue=0&svalue=00213416'
commandArray['IR send']='On'
end
end
return commandArray
```
## Hardware
Use any ATMega328-based Arduino, connect the radio, and finally connect an infrared led (in series with a resistor, like 100 Ohm) between digital pin 3 and GND.