From a8cd8956de8fa8552608dcbefad4f052a37ef761 Mon Sep 17 00:00:00 2001 From: ToniA Date: Tue, 3 Nov 2015 19:31:37 +0200 Subject: [PATCH] Sharp/IVT support, heatpumps should use 38 kHz carrier frequency --- libraries/HeatpumpIR/CarrierHeatpumpIR.cpp | 2 +- libraries/HeatpumpIR/FujitsuHeatpumpIR.cpp | 2 +- libraries/HeatpumpIR/MideaHeatpumpIR.cpp | 2 +- libraries/HeatpumpIR/MitsubishiHeatpumpIR.cpp | 2 +- .../HeatpumpIR/PanasonicCKPHeatpumpIR.cpp | 4 +- libraries/HeatpumpIR/PanasonicHeatpumpIR.cpp | 2 +- libraries/HeatpumpIR/README.md | 1 + libraries/HeatpumpIR/SamsungHeatpumpIR.cpp | 12 +- libraries/HeatpumpIR/SharpHeatpumpIR.cpp | 122 ++++++++++++++++++ libraries/HeatpumpIR/SharpHeatpumpIR.h | 42 ++++++ .../HeatpumpIR/examples/simple/simple.ino | 3 +- libraries/HeatpumpIR/keywords.txt | 1 + .../HeatpumpIRController.ino | 78 +++++++---- 13 files changed, 236 insertions(+), 37 deletions(-) create mode 100644 libraries/HeatpumpIR/SharpHeatpumpIR.cpp create mode 100644 libraries/HeatpumpIR/SharpHeatpumpIR.h diff --git a/libraries/HeatpumpIR/CarrierHeatpumpIR.cpp b/libraries/HeatpumpIR/CarrierHeatpumpIR.cpp index 244f03d..2b08763 100644 --- a/libraries/HeatpumpIR/CarrierHeatpumpIR.cpp +++ b/libraries/HeatpumpIR/CarrierHeatpumpIR.cpp @@ -141,7 +141,7 @@ void CarrierHeatpumpIR::sendCarrier(IRSender& IR, uint8_t operatingMode, uint8_t sendBuffer[8] = IR.bitReverse(checksum); // 40 kHz PWM frequency - IR.setFrequency(40); + IR.setFrequency(38); // Header IR.mark(CARRIER_AIRCON1_HDR_MARK); diff --git a/libraries/HeatpumpIR/FujitsuHeatpumpIR.cpp b/libraries/HeatpumpIR/FujitsuHeatpumpIR.cpp index dbad1ab..294491b 100644 --- a/libraries/HeatpumpIR/FujitsuHeatpumpIR.cpp +++ b/libraries/HeatpumpIR/FujitsuHeatpumpIR.cpp @@ -176,7 +176,7 @@ void FujitsuHeatpumpIR::sendFujitsuTestRun(IRSender& IR) void FujitsuHeatpumpIR::sendFujitsuMsg(IRSender& IR, uint8_t msgSize, uint8_t *msg) { // 40 kHz PWM frequency - IR.setFrequency(40); + IR.setFrequency(38); // Header IR.mark(FUJITSU_AIRCON1_HDR_MARK); diff --git a/libraries/HeatpumpIR/MideaHeatpumpIR.cpp b/libraries/HeatpumpIR/MideaHeatpumpIR.cpp index bf58bab..7f5d5c9 100644 --- a/libraries/HeatpumpIR/MideaHeatpumpIR.cpp +++ b/libraries/HeatpumpIR/MideaHeatpumpIR.cpp @@ -118,7 +118,7 @@ void MideaHeatpumpIR::sendMidea(IRSender& IR, uint8_t operatingMode, uint8_t fan void MideaHeatpumpIR::sendMidearaw(IRSender& IR, uint8_t sendBuffer[]) { // 40 kHz PWM frequency - IR.setFrequency(40); + IR.setFrequency(38); // Header IR.mark(MIDEA_AIRCON1_HDR_MARK); diff --git a/libraries/HeatpumpIR/MitsubishiHeatpumpIR.cpp b/libraries/HeatpumpIR/MitsubishiHeatpumpIR.cpp index 7823e57..23b7fee 100644 --- a/libraries/HeatpumpIR/MitsubishiHeatpumpIR.cpp +++ b/libraries/HeatpumpIR/MitsubishiHeatpumpIR.cpp @@ -188,7 +188,7 @@ void MitsubishiHeatpumpIR::sendMitsubishi(IRSender& IR, uint8_t powerMode, uint8 MitsubishiTemplate[17] = checksum; // 40 kHz PWM frequency - IR.setFrequency(40); + IR.setFrequency(38); // The Mitsubishi data is repeated twice for (int j=0; j<2; j++) { diff --git a/libraries/HeatpumpIR/PanasonicCKPHeatpumpIR.cpp b/libraries/HeatpumpIR/PanasonicCKPHeatpumpIR.cpp index 23978e9..fb62e9f 100644 --- a/libraries/HeatpumpIR/PanasonicCKPHeatpumpIR.cpp +++ b/libraries/HeatpumpIR/PanasonicCKPHeatpumpIR.cpp @@ -163,7 +163,7 @@ void PanasonicCKPHeatpumpIR::sendPanasonicCKP(IRSender& IR, uint8_t operatingMod void PanasonicCKPHeatpumpIR::sendPanasonicCKPraw(IRSender& IR, uint8_t sendBuffer[]) { // 40 kHz PWM frequency - IR.setFrequency(40); + IR.setFrequency(38); // Header, two first uint8_ts repeated IR.mark(PANASONIC_AIRCON1_HDR_MARK); @@ -228,7 +228,7 @@ void PanasonicCKPHeatpumpIR::sendPanasonicCKPOnOffTimerCancel(IRSender& IR, bool } // 40 kHz PWM frequency - IR.setFrequency(40); + IR.setFrequency(38); for (int i=0; i<6; i++) { IR.mark(PANASONIC_AIRCON1_HDR_MARK); diff --git a/libraries/HeatpumpIR/PanasonicHeatpumpIR.cpp b/libraries/HeatpumpIR/PanasonicHeatpumpIR.cpp index ee0be97..ff4c292 100644 --- a/libraries/HeatpumpIR/PanasonicHeatpumpIR.cpp +++ b/libraries/HeatpumpIR/PanasonicHeatpumpIR.cpp @@ -208,7 +208,7 @@ void PanasonicHeatpumpIR::sendPanasonic(IRSender& IR, uint8_t operatingMode, uin panasonicTemplate[26] = checksum; // 40 kHz PWM frequency - IR.setFrequency(40); + IR.setFrequency(38); // Header IR.mark(PANASONIC_AIRCON2_HDR_MARK); diff --git a/libraries/HeatpumpIR/README.md b/libraries/HeatpumpIR/README.md index f56737e..6047150 100644 --- a/libraries/HeatpumpIR/README.md +++ b/libraries/HeatpumpIR/README.md @@ -12,6 +12,7 @@ Currently supports at least these models * Fujitsu Nocria AWYZ14 (remote control P/N AR-PZ2) * Mitsubishi MSZ FD-25, probably also FD-35 (remote control P/N KM09D 0052376) * Hisense AUD (remote control Y-H1-01, Y-H1-02(E), Y-J1, Y-E4-07) probably AUC model +* Sharp AY-ZP40KR (remote control P/N CRMC-A788JBEZ), possibly also IVT ## Instructions diff --git a/libraries/HeatpumpIR/SamsungHeatpumpIR.cpp b/libraries/HeatpumpIR/SamsungHeatpumpIR.cpp index eb943bc..859dc7e 100644 --- a/libraries/HeatpumpIR/SamsungHeatpumpIR.cpp +++ b/libraries/HeatpumpIR/SamsungHeatpumpIR.cpp @@ -90,8 +90,8 @@ void SamsungHeatpumpIR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t operati void SamsungHeatpumpIR::sendSamsung(IRSender& IR, uint8_t powerMode, uint8_t operatingMode, uint8_t fanSpeed, uint8_t temperature, uint8_t swingV) { uint8_t SamsungTemplate[] = { 0x02, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, // Header part - 0x01, 0xD2, 0x0F, 0x00, 0x00, 0x00, 0x00, // Always the same data on POWER messages - 0x01, 0x00, 0xFE, 0x71, 0x00, 0x00, 0x00 }; // The actual data is in this part, on uint8_ts 14-20 + 0x01, 0xD2, 0x0F, 0x00, 0x00, 0x00, 0x00, // Always the same data on POWER messages + 0x01, 0x00, 0xFE, 0x71, 0x00, 0x00, 0x00 }; // The actual data is in this part, on uint8_ts 14-20 uint8_t SamsungChecksum = 0; @@ -114,15 +114,15 @@ void SamsungHeatpumpIR::sendSamsung(IRSender& IR, uint8_t powerMode, uint8_t ope // Set the vertical swing mode on the template message SamsungTemplate[16] = swingV; - // Calculate the uint8_t 15 checksum + // Calculate the byte 15 checksum // Count the number of ONE bits on message uint8_ts 15-20 for (uint8_t j=15; j<21; j++) { - uint8_t Samsunguint8_t = SamsungTemplate[j]; + uint8_t Samsungbyte = SamsungTemplate[j]; for (uint8_t i=0; i<8; i++) { - if ( (Samsunguint8_t & 0x01) == 0x01 ) { + if ( (Samsungbyte & 0x01) == 0x01 ) { SamsungChecksum++; } - Samsunguint8_t >>= 1; + Samsungbyte >>= 1; } } diff --git a/libraries/HeatpumpIR/SharpHeatpumpIR.cpp b/libraries/HeatpumpIR/SharpHeatpumpIR.cpp new file mode 100644 index 0000000..a9a937b --- /dev/null +++ b/libraries/HeatpumpIR/SharpHeatpumpIR.cpp @@ -0,0 +1,122 @@ +#include + + +SharpHeatpumpIR::SharpHeatpumpIR() : HeatpumpIR() +{ + static const char PROGMEM model[] PROGMEM = "sharp"; + static const char PROGMEM info[] PROGMEM = "{\"mdl\":\"sharp\",\"dn\":\"Sharp AY-ZP40KR\",\"mT\":18,\"xT\":32,\"fs\":3,\"maint\":[10]}}"; + + _model = model; + _info = info; +} + + +void SharpHeatpumpIR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd, uint8_t swingVCmd, uint8_t swingHCmd) +{ + // Sensible defaults for the heat pump mode + + uint8_t powerMode = SHARP_AIRCON1_MODE_ON; + uint8_t operatingMode = SHARP_AIRCON1_MODE_HEAT; + uint8_t fanSpeed = SHARP_AIRCON1_FAN_AUTO; + uint8_t temperature = 23; + + if (powerModeCmd == 0) + { + powerMode = SHARP_AIRCON1_MODE_OFF; + } + + switch (operatingModeCmd) + { + case MODE_HEAT: + operatingMode = SHARP_AIRCON1_MODE_HEAT; + break; + case MODE_COOL: + operatingMode = SHARP_AIRCON1_MODE_COOL; + break; + case MODE_DRY: + operatingMode = SHARP_AIRCON1_MODE_DRY; + temperatureCmd = 10; + break; + case MODE_FAN: + operatingMode = SHARP_AIRCON1_MODE_COOL; + // Temperature needs to be set to 32 degrees for 'simulated' FAN mode + temperatureCmd = 32; + break; + case MODE_MAINT: // Maintenance mode is just the heat mode at +8 or +10, FAN5 + operatingMode |= SHARP_AIRCON1_MODE_HEAT; + temperature = 10; + fanSpeedCmd = FAN_5; + break; + } + + switch (fanSpeedCmd) + { + case FAN_AUTO: + fanSpeed = SHARP_AIRCON1_FAN_AUTO; + break; + case FAN_1: + fanSpeed = SHARP_AIRCON1_FAN1; + break; + case FAN_2: + fanSpeed = SHARP_AIRCON1_FAN2; + break; + case FAN_3: + fanSpeed = SHARP_AIRCON1_FAN3; + break; + } + + if ( temperatureCmd > 16 && temperatureCmd < 32) + { + temperature = temperatureCmd; + } + + sendSharp(IR, powerMode, operatingMode, fanSpeed, temperature); +} + +void SharpHeatpumpIR::sendSharp(IRSender& IR, uint8_t powerMode, uint8_t operatingMode, uint8_t fanSpeed, uint8_t temperature) +{ + uint8_t SharpTemplate[] = { 0xAA, 0x5A, 0xCF, 0x10, 0x00, 0x00, 0x00, 0x06, 0x08, 0x80, 0x04, 0xF0, 0x01 }; + // 0 1 2 3 4 5 6 7 8 9 10 11 12 + + uint8_t checksum = 0x00; + + // Set the power mode on the template message + SharpTemplate[5] = powerMode; + + // Set the fan speed & operating mode on the template message + SharpTemplate[6] = fanSpeed | operatingMode; + + // Set the temperature on the template message + if (temperature == 10) { + SharpTemplate[4] = 0x00; // Maintenance mode temperature + } else { + SharpTemplate[4] = (temperature - 17); + } + + // Calculate the checksum + for (int i=0; i<12; i++) { + checksum ^= SharpTemplate[i]; + } + + checksum ^= SharpTemplate[12] & 0x0F; + checksum ^= (checksum >> 4); + checksum &= 0x0F; + + SharpTemplate[12] |= (checksum << 4); + + // 38 kHz PWM frequency + IR.setFrequency(38); + + // Header + IR.mark(SHARP_AIRCON1_HDR_MARK); + IR.space(SHARP_AIRCON1_HDR_SPACE); + + // Data + for (unsigned int i=0; i + + +// Sharp timing constants +#define SHARP_AIRCON1_HDR_MARK 3540 // 3820 +#define SHARP_AIRCON1_HDR_SPACE 1720 // 1680 +#define SHARP_AIRCON1_BIT_MARK 460 // 420 +#define SHARP_AIRCON1_ONE_SPACE 1400 // 1250 +#define SHARP_AIRCON1_ZERO_SPACE 430 // 330 + +// Sharp codes +#define SHARP_AIRCON1_MODE_HEAT 0x01 +#define SHARP_AIRCON1_MODE_COOL 0x02 +#define SHARP_AIRCON1_MODE_DRY 0x03 +#define SHARP_AIRCON1_MODE_OFF 0x21 // Power OFF +#define SHARP_AIRCON1_MODE_ON 0x31 // Power ON +#define SHARP_AIRCON1_FAN_AUTO 0x20 // Fan speed +#define SHARP_AIRCON1_FAN1 0x30 +#define SHARP_AIRCON1_FAN2 0x50 +#define SHARP_AIRCON1_FAN3 0x70 + + +class SharpHeatpumpIR : public HeatpumpIR +{ + public: + SharpHeatpumpIR(); + void send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd, uint8_t swingVCmd, uint8_t swingHCmd); + + private: + void sendSharp(IRSender& IR, uint8_t powerMode, uint8_t operatingMode, uint8_t fanSpeed, uint8_t temperature); +}; + +#endif diff --git a/libraries/HeatpumpIR/examples/simple/simple.ino b/libraries/HeatpumpIR/examples/simple/simple.ino index 229c936..b7723d1 100644 --- a/libraries/HeatpumpIR/examples/simple/simple.ino +++ b/libraries/HeatpumpIR/examples/simple/simple.ino @@ -7,6 +7,7 @@ #include #include #include +#include IRSender irSender(3); // IR led on Duemilanove digital pin 3 @@ -14,7 +15,7 @@ IRSender irSender(3); // IR led on Duemilanove digital pin 3 HeatpumpIR *heatpumpIR[] = {new PanasonicCKPHeatpumpIR(), new PanasonicDKEHeatpumpIR(), new PanasonicJKEHeatpumpIR(), new PanasonicNKEHeatpumpIR(), new CarrierHeatpumpIR(), new MideaHeatpumpIR(), new FujitsuHeatpumpIR(), new MitsubishiFDHeatpumpIR(), new MitsubishiFEHeatpumpIR(), - new SamsungHeatpumpIR(), NULL}; + new SamsungHeatpumpIR(), new SharpHeatpumpIR(), NULL}; void setup() { diff --git a/libraries/HeatpumpIR/keywords.txt b/libraries/HeatpumpIR/keywords.txt index b7e0632..7fa5eb1 100644 --- a/libraries/HeatpumpIR/keywords.txt +++ b/libraries/HeatpumpIR/keywords.txt @@ -11,6 +11,7 @@ MitsubishiHeatpumpIR KEYWORD1 MitsubishiFDHeatpumpIR KEYWORD1 MitsubishiFEHeatpumpIR KEYWORD1 SamsungHeatpumpIR KEYWORD1 +SharpHeatpumpIR KEYWORD1 IRSender KEYWORD1 diff --git a/libraries/MySensors/examples/HeatpumpIRController/HeatpumpIRController.ino b/libraries/MySensors/examples/HeatpumpIRController/HeatpumpIRController.ino index 79e153f..d14953b 100644 --- a/libraries/MySensors/examples/HeatpumpIRController/HeatpumpIRController.ino +++ b/libraries/MySensors/examples/HeatpumpIRController/HeatpumpIRController.ino @@ -1,6 +1,38 @@ -#include +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - Toni A - https://github.com/ToniA/arduino-heatpumpir + * + * DESCRIPTION + * Heatpump controller + */ -// HeatpumpIR libraries, https://github.com/ToniA/arduino-heatpumpir +// Enable debug prints to serial monitor +#define MY_DEBUG + +// Enable and select radio type attached +#define MY_RADIO_NRF24 +//#define MY_RADIO_RFM69 + +// HeatpumpIR libraries, #include #include #include @@ -8,19 +40,19 @@ #include #include #include +#include // Timer library, https://github.com/JChristensen/Timer #include // MySensors libraries -#include #include +#include // Child ID's of this node #define CHILD_1 1 // MySensors definitions -MySensor gw; MyMessage irMsg(CHILD_1, V_IR_RECEIVE); // -- Hacks for Domoticz start @@ -41,7 +73,8 @@ HeatpumpIR *heatpumpIR[] = { new PanasonicCKPHeatpumpIR(), // 0, keep this if yo new FujitsuHeatpumpIR(), // 6 new MitsubishiFDHeatpumpIR(), // 7 new MitsubishiFEHeatpumpIR(), // 8 - new SamsungHeatpumpIR() // 9 + new SamsungHeatpumpIR(), // 9 + new SharpHeatpumpIR() // 10 }; // IR led on PWM output-capable digital pin 3 @@ -54,6 +87,7 @@ int8_t panasonicCKPTimer = 0; // Number of supported models byte models = 0; + void setup() { Serial.begin(115200); @@ -63,33 +97,31 @@ void setup() 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"); - - // -- Hacks for Domoticz start - 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")); + send(textMsg.setSensor(CHILD_2).set("00000000")); // -- Hacks for Domoticz end } +void presentation() { + // Send the sketch version information to the gateway and Controller + sendSketchInfo("Heatpump Sensor", "1.0"); + + // Register a sensors to the MySensors Gateway + present(CHILD_1, S_IR, "IR sender"); + + // -- Hacks for Domoticz start + present(CHILD_2, S_INFO, "IR data"); + present(CHILD_3, S_LIGHT, "IR send"); +} void loop() { - gw.process(); timer.update(); } // Handle incoming messages from the MySensors Gateway -void incomingMessage(const MyMessage &message) { +void receive(const MyMessage &message) { const char *irData; @@ -105,7 +137,7 @@ void incomingMessage(const MyMessage &message) { 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); + 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...")); @@ -117,7 +149,7 @@ void incomingMessage(const MyMessage &message) { sendHeatpumpIRCommand(irData); // Set the Domoticz switch back to 'OFF' state - gw.send(sendMsg.setSensor(CHILD_3).set(0)); + send(sendMsg.setSensor(CHILD_3).set(0)); } // -- Hacks for Domoticz end } @@ -207,4 +239,4 @@ void panasonicCancelTimer() panasonicCKPHeatpumpIR->sendPanasonicCKPCancelTimer(irSender); Serial.println(F("The TIMER led should now be OFF")); -} \ No newline at end of file +}