IR Update library and usage instructions

This commit is contained in:
jimmys01
2019-08-26 14:06:23 +03:00
parent 1a1b7ce219
commit 0e054ea2af
25 changed files with 1105 additions and 114 deletions
+1
View File
@@ -56,6 +56,7 @@ jobs:
- arduino --verify --board $BD $PWD/examples/TurnOnMitsubishiHeavyAc/TurnOnMitsubishiHeavyAc.ino 2> /dev/null
- arduino --verify --board $BD $PWD/examples/DumbIRRepeater/DumbIRRepeater.ino 2> /dev/null
- arduino --verify --board $BD $PWD/examples/SmartIRRepeater/SmartIRRepeater.ino 2> /dev/null
- arduino --verify --board $BD $PWD/examples/CommonAcControl/CommonAcControl.ino 2> /dev/null
- script:
# Check the version numbers match.
- LIB_VERSION=$(egrep "^#define\s+_IRREMOTEESP8266_VERSION_\s+" src/IRremoteESP8266.h | cut -d\" -f2)
@@ -0,0 +1,81 @@
/* Copyright 2019 David Conran
*
* This example code demonstrates how to use the "Common" IRac class to control
* various air conditions. The IRac class does not support all the features
* for every protocol. Some have more detailed support that what the "Common"
* interface offers, and some only have a limited subset of the "Common" options.
*
* This example code will:
* o Try to turn on, then off every fully supported A/C protocol we know of.
* o It will try to put the A/C unit into Cooling mode at 25C, with a medium
* fan speed, and no fan swinging.
* Note: Some protocols support multiple models, only the first model is tried.
*
*/
#include <Arduino.h>
#include <IRremoteESP8266.h>
#include <IRac.h>
#include <IRutils.h>
const uint16_t kIrLed = 4; // The ESP GPIO pin to use that controls the IR LED.
IRac ac(kIrLed); // Create a A/C object using GPIO to sending messages with.
stdAc::state_t state; // Where we will store the desired state of the A/C.
stdAc::state_t prev; // Where we will store the previous state of the A/C.
void setup() {
Serial.begin(115200);
delay(200);
// Set up what we want to send.
// See state_t, opmode_t, fanspeed_t, swingv_t, & swingh_t in IRsend.h for
// all the various options.
state.protocol = decode_type_t::DAIKIN; // Set a protocol to use.
state.model = 1; // Some A/C's have different models. Let's try using just 1.
state.mode = stdAc::opmode_t::kCool; // Run in cool mode initially.
state.celsius = true; // Use Celsius for units of temp. False = Fahrenheit
state.degrees = 25; // 25 degrees.
state.fanspeed = stdAc::fanspeed_t::kMedium; // Start with the fan at medium.
state.swingv = stdAc::swingv_t::kOff; // Don't swing the fan up or down.
state.swingh = stdAc::swingh_t::kOff; // Don't swing the fan left or right.
state.light = false; // Turn off any LED/Lights/Display that we can.
state.beep = false; // Turn off any beep from the A/C if we can.
state.econo = false; // Turn off any economy modes if we can.
state.filter = false; // Turn off any Ion/Mold/Health filters if we can.
state.turbo = false; // Don't use any turbo/powerful/etc modes.
state.quiet = false; // Don't use any quiet/silent/etc modes.
state.sleep = -1; // Don't set any sleep time or modes.
state.clean = false; // Turn off any Cleaning options if we can.
state.clock = -1; // Don't set any current time if we can avoid it.
state.power = false; // Initially start with the unit off.
prev = state; // Make sure we have a valid previous state.
}
void loop() {
// For every protocol the library has ...
for (int i = 1; i < kLastDecodeType; i++) {
decode_type_t protocol = (decode_type_t)i;
// If the protocol is supported by the IRac class ...
if (ac.isProtocolSupported(protocol)) {
state.protocol = protocol; // Change the protocol used.
Serial.println("Protocol " + String(protocol) + " / " +
typeToString(protocol));
state.power = true; // We want to turn on the A/C unit.
// Have the IRac class create and send a message.
// We need a `prev` state as some A/Cs use toggle messages.
// e.g. On & Off are the same message. When given the previous state,
// it will try to do the correct thing for you.
ac.sendAc(state, &prev); // Construct and send the message.
Serial.println("Sent a message to turn ON the A/C unit.");
prev = state; // Copy new state over the previous one.
delay(5000); // Wait 5 seconds.
state.power = false; // Now we want to turn the A/C off.
ac.sendAc(state, &prev); // Construct and send the message.
Serial.println("Sent a message to turn OFF the A/C unit.");
prev = state; // Copy new state over the previous one.
delay(1000); // Wait 1 second.
}
}
Serial.println("Starting from the begining again ...");
}
@@ -0,0 +1,18 @@
[platformio]
src_dir = .
[env]
lib_extra_dirs = ../../
lib_ldf_mode = deep+
lib_ignore = examples
build_flags =
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
[env:esp32dev]
platform = espressif32
framework = arduino
board = esp32dev
@@ -5,6 +5,9 @@
#ifndef EXAMPLES_IRMQTTSERVER_IRMQTTSERVER_H_
#define EXAMPLES_IRMQTTSERVER_IRMQTTSERVER_H_
#if defined(ESP8266)
#include <ESP8266WiFi.h>
#endif // ESP8266
#include <IRremoteESP8266.h>
#include <IRrecv.h>
#include <IRsend.h>
@@ -156,6 +159,16 @@ const uint16_t kMinUnknownSize = 2 * 10;
// ------------------------ Advanced Usage Only --------------------------------
// Reports the input voltage to the ESP chip. **NOT** the input voltage
// to the development board (e.g. NodeMCU, D1 Mini etc) which are typically
// powered by USB (5V) which is then lowered to 3V via a Low Drop Out (LDO)
// Voltage regulator. Hence, this feature is turned off by default as it
// make little sense for most users as it really isn't the actual input voltage.
// E.g. For purposes of monitoring a battery etc.
// Note: Turning on the feature costs ~250 bytes of prog space.
#define REPORT_VCC false // Do we report Vcc via html info page & MQTT?
// Keywords for MQTT topics, html arguments, or config file.
#define KEY_PROTOCOL "protocol"
#define KEY_MODEL "model"
#define KEY_POWER "power"
@@ -175,6 +188,7 @@ const uint16_t kMinUnknownSize = 2 * 10;
#define KEY_CELSIUS "use_celsius"
#define KEY_JSON "json"
#define KEY_RESEND "resend"
#define KEY_VCC "vcc"
// HTML arguments we will parse for IR code information.
#define KEY_TYPE "type" // KEY_PROTOCOL is also checked too.
@@ -297,6 +311,9 @@ void sendJsonState(const stdAc::state_t state, const String topic,
const bool retain = false, const bool ha_mode = true);
#endif // MQTT_CLIMATE_JSON
#endif // MQTT_ENABLE
#if REPORT_VCC
String vccToString(void);
#endif // REPORT_VCC
bool isSerialGpioUsedByIr(void);
void debug(const char *str);
void saveWifiConfigCallback(void);
@@ -347,6 +347,10 @@
using irutils::msToString;
#if REPORT_VCC
ADC_MODE(ADC_VCC);
#endif // REPORT_VCC
// Globals
#if defined(ESP8266)
ESP8266WebServer server(kHttpPort);
@@ -913,7 +917,7 @@ String htmlSelectGpio(const String name, const int16_t def,
String htmlSelectMode(const String name, const stdAc::opmode_t def) {
String html = "<select name='" + name + "'>";
for (int8_t i = -1; i <= 4; i++) {
for (int8_t i = -1; i <= (int8_t)stdAc::opmode_t::kLastOpmodeEnum; i++) {
String mode = IRac::opmodeToString((stdAc::opmode_t)i);
html += htmlOptionItem(mode, mode, (stdAc::opmode_t)i == def);
}
@@ -923,7 +927,7 @@ String htmlSelectMode(const String name, const stdAc::opmode_t def) {
String htmlSelectFanspeed(const String name, const stdAc::fanspeed_t def) {
String html = "<select name='" + name + "'>";
for (int8_t i = 0; i <= 5; i++) {
for (int8_t i = 0; i <= (int8_t)stdAc::fanspeed_t::kLastFanspeedEnum; i++) {
String speed = IRac::fanspeedToString((stdAc::fanspeed_t)i);
html += htmlOptionItem(speed, speed, (stdAc::fanspeed_t)i == def);
}
@@ -933,7 +937,7 @@ String htmlSelectFanspeed(const String name, const stdAc::fanspeed_t def) {
String htmlSelectSwingv(const String name, const stdAc::swingv_t def) {
String html = "<select name='" + name + "'>";
for (int8_t i = -1; i <= 5; i++) {
for (int8_t i = -1; i <= (int8_t)stdAc::swingv_t::kLastSwingvEnum; i++) {
String swing = IRac::swingvToString((stdAc::swingv_t)i);
html += htmlOptionItem(swing, swing, (stdAc::swingv_t)i == def);
}
@@ -943,7 +947,7 @@ String htmlSelectSwingv(const String name, const stdAc::swingv_t def) {
String htmlSelectSwingh(const String name, const stdAc::swingh_t def) {
String html = "<select name='" + name + "'>";
for (int8_t i = -1; i <= 5; i++) {
for (int8_t i = -1; i <= (int8_t)stdAc::swingh_t::kLastSwinghEnum; i++) {
String swing = IRac::swinghToString((stdAc::swingh_t)i);
html += htmlOptionItem(swing, swing, (stdAc::swingh_t)i == def);
}
@@ -1121,6 +1125,10 @@ uint32_t maxSketchSpace(void) {
#endif // defined(ESP8266)
}
#if REPORT_VCC
String vccToString(void) { return String(ESP.getVcc() / 1000.0); }
#endif // REPORT_VCC
// Info web page
void handleInfo(void) {
String html = htmlHeader(F("IR MQTT server info"));
@@ -1175,6 +1183,11 @@ void handleInfo(void) {
"Off"
#endif // DEBUG
"<br>"
#if REPORT_VCC
"Vcc: ";
html += vccToString();
html += "V<br>"
#endif // REPORT_VCC
"</p>"
#if MQTT_ENABLE
"<h4>MQTT Information</h4>"
@@ -1252,7 +1265,8 @@ void doRestart(const char* str, const bool serial_only) {
void handleReset(void) {
#if HTML_PASSWORD_ENABLE
if (!server.authenticate(HttpUsername, HttpPassword)) {
debug("Basic HTTP authentication failure for " + kUrlWipe);
debug(("Basic HTTP authentication failure for " +
String(kUrlWipe)).c_str());
return server.requestAuthentication();
}
#endif
@@ -1281,7 +1295,8 @@ void handleReset(void) {
void handleReboot() {
#if HTML_PASSWORD_ENABLE
if (!server.authenticate(HttpUsername, HttpPassword)) {
debug("Basic HTTP authentication failure for " + kUrlReboot);
debug(("Basic HTTP authentication failure for " +
String(kUrlReboot)).c_str());
return server.requestAuthentication();
}
#endif
@@ -2167,6 +2182,9 @@ void doBroadcast(TimerMs *timer, const uint32_t interval,
debug("Sending MQTT stat update broadcast.");
sendClimate(state, state, MqttClimateStat,
retain, true, false);
#if REPORT_VCC
sendString(MqttClimateStat + KEY_VCC, vccToString(), false);
#endif // REPORT_VCC
#if MQTT_CLIMATE_JSON
sendJsonState(state, MqttClimateStat + KEY_JSON);
#endif // MQTT_CLIMATE_JSON
@@ -2322,29 +2340,22 @@ void sendMQTTDiscovery(const char *topic) {
"{"
"\"~\":\"" + MqttClimate + "\","
"\"name\":\"" + MqttHAName + "\","
"\"pow_cmd_t\":\"~" MQTT_CLIMATE "/" MQTT_CLIMATE_CMND "/" KEY_POWER "\","
"\"mode_cmd_t\":\"~" MQTT_CLIMATE "/" MQTT_CLIMATE_CMND "/" KEY_MODE "\","
"\"mode_stat_t\":\"~" MQTT_CLIMATE "/" MQTT_CLIMATE_STAT "/" KEY_MODE
"\","
"\"pow_cmd_t\":\"~/" MQTT_CLIMATE_CMND "/" KEY_POWER "\","
"\"mode_cmd_t\":\"~/" MQTT_CLIMATE_CMND "/" KEY_MODE "\","
"\"mode_stat_t\":\"~/" MQTT_CLIMATE_STAT "/" KEY_MODE "\","
"\"modes\":[\"off\",\"auto\",\"cool\",\"heat\",\"dry\",\"fan_only\"],"
"\"temp_cmd_t\":\"~" MQTT_CLIMATE "/" MQTT_CLIMATE_CMND "/" KEY_TEMP "\","
"\"temp_stat_t\":\"~" MQTT_CLIMATE "/" MQTT_CLIMATE_STAT "/" KEY_TEMP
"\","
"\"temp_cmd_t\":\"~/" MQTT_CLIMATE_CMND "/" KEY_TEMP "\","
"\"temp_stat_t\":\"~/" MQTT_CLIMATE_STAT "/" KEY_TEMP "\","
"\"min_temp\":\"16\","
"\"max_temp\":\"30\","
"\"temp_step\":\"1\","
"\"fan_mode_cmd_t\":\"~" MQTT_CLIMATE "/" MQTT_CLIMATE_CMND "/"
KEY_FANSPEED "\","
"\"fan_mode_stat_t\":\"~" MQTT_CLIMATE "/" MQTT_CLIMATE_STAT "/"
KEY_FANSPEED "\","
"\"fan_mode_cmd_t\":\"~/" MQTT_CLIMATE_CMND "/" KEY_FANSPEED "\","
"\"fan_mode_stat_t\":\"~/" MQTT_CLIMATE_STAT "/" KEY_FANSPEED "\","
"\"fan_modes\":[\"auto\",\"min\",\"low\",\"medium\",\"high\",\"max\"],"
"\"swing_mode_cmd_t\":\"~" MQTT_CLIMATE "/" MQTT_CLIMATE_CMND "/"
KEY_SWINGV "\","
"\"swing_mode_stat_t\":\"~" MQTT_CLIMATE "/" MQTT_CLIMATE_STAT "/"
KEY_SWINGV "\","
"\"swing_mode_cmd_t\":\"~/" MQTT_CLIMATE_CMND "/" KEY_SWINGV "\","
"\"swing_mode_stat_t\":\"~/" MQTT_CLIMATE_STAT "/" KEY_SWINGV "\","
"\"swing_modes\":["
"\"off\",\"auto\",\"highest\",\"high\",\"middle\",\"low\",\"lowest\""
"]"
"\"off\",\"auto\",\"highest\",\"high\",\"middle\",\"low\",\"lowest\"]"
"}").c_str())) {
mqttLog("MQTT climate discovery successful sent.");
hasDiscoveryBeenSent = true;
+64 -6
View File
@@ -15,6 +15,7 @@
#include "IRsend.h"
#include "IRremoteESP8266.h"
#include "IRutils.h"
#include "ir_Amcor.h"
#include "ir_Argo.h"
#include "ir_Coolix.h"
#include "ir_Daikin.h"
@@ -46,7 +47,10 @@ IRac::IRac(const uint16_t pin, const bool inverted, const bool use_modulation) {
// Is the given protocol supported by the IRac class?
bool IRac::isProtocolSupported(const decode_type_t protocol) {
switch (protocol) {
#if SEND_ARGO
#if SEND_AMCOR
case decode_type_t::AMCOR:
#endif
#if SEND_AMCOR
case decode_type_t::ARGO:
#endif
#if SEND_COOLIX
@@ -140,6 +144,27 @@ bool IRac::isProtocolSupported(const decode_type_t protocol) {
}
}
#if SEND_AMCOR
void IRac::amcor(IRAmcorAc *ac,
const bool on, const stdAc::opmode_t mode, const float degrees,
const stdAc::fanspeed_t fan) {
ac->setPower(on);
ac->setMode(ac->convertMode(mode));
ac->setTemp(degrees);
ac->setFan(ac->convertFan(fan));
// No Swing setting available.
// No Quiet setting available.
// No Light setting available.
// No Filter setting available.
// No Turbo setting available.
// No Economy setting available.
// No Clean setting available.
// No Beep setting available.
// No Sleep setting available.
ac->send();
}
#endif // SEND_AMCOR
#if SEND_ARGO
void IRac::argo(IRArgoAC *ac,
const bool on, const stdAc::opmode_t mode, const float degrees,
@@ -400,6 +425,7 @@ void IRac::fujitsu(IRFujitsuAC *ac, const fujitsu_ac_remote_model_t model,
// No Beep setting available.
// No Sleep setting available.
// No Clock setting available.
ac->on(); // Ref: Issue #860
} else {
// Off is special case/message. We don't need to send other messages.
ac->off();
@@ -801,7 +827,7 @@ void IRac::tcl112(IRTcl112Ac *ac,
void IRac::teco(IRTecoAc *ac,
const bool on, const stdAc::opmode_t mode, const float degrees,
const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
const int16_t sleep) {
const bool light, const int16_t sleep) {
ac->setPower(on);
ac->setMode(ac->convertMode(mode));
ac->setTemp(degrees);
@@ -810,7 +836,7 @@ void IRac::teco(IRTecoAc *ac,
// No Horizontal swing setting available.
// No Quiet setting available.
// No Turbo setting available.
// No Light setting available.
ac->setLight(light);
// No Filter setting available.
// No Clean setting available.
// No Beep setting available.
@@ -1014,6 +1040,14 @@ bool IRac::sendAc(const decode_type_t vendor, const int16_t model,
if (mode == stdAc::opmode_t::kOff) on = false;
// Per vendor settings & setup.
switch (vendor) {
#if SEND_AMCOR
case AMCOR:
{
IRAmcorAc ac(_pin, _inverted, _modulation);
amcor(&ac, on, mode, degC, fan);
break;
}
#endif // SEND_AMCOR
#if SEND_ARGO
case ARGO:
{
@@ -1247,7 +1281,7 @@ bool IRac::sendAc(const decode_type_t vendor, const int16_t model,
{
IRTecoAc ac(_pin, _inverted, _modulation);
ac.begin();
teco(&ac, on, mode, degC, fan, swingv, sleep);
teco(&ac, on, mode, degC, fan, swingv, light, sleep);
break;
}
#endif // SEND_TECO
@@ -1421,11 +1455,20 @@ stdAc::swingh_t IRac::strToSwingH(const char *str,
// Assumes str is the model or an integer >= 1.
int16_t IRac::strToModel(const char *str, const int16_t def) {
// Gree
if (!strcasecmp(str, "YAW1F")) {
return gree_ac_remote_model_t::YAW1F;
} else if (!strcasecmp(str, "YBOFB")) {
return gree_ac_remote_model_t::YBOFB;
// Fujitsu A/C models
if (!strcasecmp(str, "ARRAH2E")) {
} else if (!strcasecmp(str, "ARRAH2E")) {
return fujitsu_ac_remote_model_t::ARRAH2E;
} else if (!strcasecmp(str, "ARDB1")) {
return fujitsu_ac_remote_model_t::ARDB1;
} else if (!strcasecmp(str, "ARREB1E")) {
return fujitsu_ac_remote_model_t::ARREB1E;
} else if (!strcasecmp(str, "ARJW2")) {
return fujitsu_ac_remote_model_t::ARJW2;
// Panasonic A/C families
} else if (!strcasecmp(str, "LKE") || !strcasecmp(str, "PANASONICLKE")) {
return panasonic_ac_remote_model_t::kPanasonicLke;
@@ -1545,7 +1588,7 @@ String IRac::swinghToString(const stdAc::swingh_t swingh) {
case stdAc::swingh_t::kRightMax:
return F("rightmax");
case stdAc::swingh_t::kWide:
return F("leftright");
return F("wide");
default:
return F("unknown");
}
@@ -1559,6 +1602,13 @@ namespace IRAcUtils {
// A string with the human description of the A/C message. "" if we can't.
String resultAcToString(const decode_results * const result) {
switch (result->decode_type) {
#if DECODE_AMCOR
case decode_type_t::AMCOR: {
IRAmcorAc ac(0);
ac.setRaw(result->state);
return ac.toString();
}
#endif // DECODE_AMCOR
#if DECODE_ARGO
case decode_type_t::ARGO: {
IRArgoAC ac(0);
@@ -1788,6 +1838,14 @@ namespace IRAcUtils {
const stdAc::state_t *prev) {
if (decode == NULL || result == NULL) return false; // Safety check.
switch (decode->decode_type) {
#if DECODE_AMCOR
case decode_type_t::AMCOR: {
IRAmcorAc ac(kGpioUnused);
ac.setRaw(decode->state);
*result = ac.toCommon();
break;
}
#endif // DECODE_AMCOR
#if DECODE_ARGO
case decode_type_t::ARGO: {
IRArgoAC ac(kGpioUnused);
+7 -1
View File
@@ -7,6 +7,7 @@
#include <Arduino.h>
#endif
#include "IRremoteESP8266.h"
#include "ir_Amcor.h"
#include "ir_Argo.h"
#include "ir_Coolix.h"
#include "ir_Daikin.h"
@@ -73,6 +74,11 @@ class IRac {
uint16_t _pin;
bool _inverted;
bool _modulation;
#if SEND_AMCOR
void amcor(IRAmcorAc *ac,
const bool on, const stdAc::opmode_t mode, const float degrees,
const stdAc::fanspeed_t fan);
#endif // SEND_AMCOR
#if SEND_ARGO
void argo(IRArgoAC *ac,
const bool on, const stdAc::opmode_t mode, const float degrees,
@@ -260,7 +266,7 @@ void electra(IRElectraAc *ac,
void teco(IRTecoAc *ac,
const bool on, const stdAc::opmode_t mode, const float degrees,
const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
const int16_t sleep = -1);
const bool light, const int16_t sleep = -1);
#endif // SEND_TECO
#if SEND_TOSHIBA_AC
void toshiba(IRToshibaAC *ac,
+9 -1
View File
@@ -49,6 +49,8 @@ namespace stdAc {
kHeat = 2,
kDry = 3,
kFan = 4,
// Add new entries before this one, and update it to point to the last entry
kLastOpmodeEnum = kFan,
};
enum class fanspeed_t {
@@ -58,6 +60,8 @@ namespace stdAc {
kMedium = 3,
kHigh = 4,
kMax = 5,
// Add new entries before this one, and update it to point to the last entry
kLastFanspeedEnum = kMax,
};
enum class swingv_t {
@@ -68,6 +72,8 @@ namespace stdAc {
kMiddle = 3,
kLow = 4,
kLowest = 5,
// Add new entries before this one, and update it to point to the last entry
kLastSwingvEnum = kLowest,
};
enum class swingh_t {
@@ -78,7 +84,9 @@ namespace stdAc {
kMiddle = 3,
kRight = 4,
kRightMax = 5,
kWide = 6,
kWide = 6, // a.k.a. left & right at the same time.
// Add new entries before this one, and update it to point to the last entry
kLastSwinghEnum = kWide,
};
// Structure to hold a common A/C state.
+242 -2
View File
@@ -5,6 +5,8 @@
// Brand: Amcor, Model: TAC-495 remote
// Brand: Amcor, Model: TAC-444 remote
#include "ir_Amcor.h"
#include <algorithm>
#include "IRrecv.h"
#include "IRsend.h"
#include "IRutils.h"
@@ -22,6 +24,11 @@ const uint16_t kAmcorFooterMark = 1900;
const uint16_t kAmcorGap = 34300;
const uint8_t kAmcorTolerance = 40;
using irutils::addBoolToString;
using irutils::addModeToString;
using irutils::addFanToString;
using irutils::addTempToString;
#if SEND_AMCOR
// Send a Amcor HVAC formatted message.
//
@@ -30,7 +37,7 @@ const uint8_t kAmcorTolerance = 40;
// nbytes: The byte size of the array being sent. typically kAmcorStateLength.
// repeat: The number of times the message is to be repeated.
//
// Status: Alpha / Needs testing.
// Status: STABLE / Reported as working.
//
void IRsend::sendAmcor(const unsigned char data[], const uint16_t nbytes,
const uint16_t repeat) {
@@ -52,7 +59,7 @@ void IRsend::sendAmcor(const unsigned char data[], const uint16_t nbytes,
// Returns:
// boolean: True if it can decode it, false if it can't.
//
// Status: BETA / Seems to be working.
// Status: STABLE / Reported as working.
//
bool IRrecv::decodeAmcor(decode_results *results, uint16_t nbits,
bool strict) {
@@ -75,6 +82,10 @@ bool IRrecv::decodeAmcor(decode_results *results, uint16_t nbits,
if (!used) return false;
offset += used;
if (strict) {
if (!IRAmcorAc::validChecksum(results->state)) return false;
}
// Success
results->bits = nbits;
results->decode_type = AMCOR;
@@ -84,3 +95,232 @@ bool IRrecv::decodeAmcor(decode_results *results, uint16_t nbits,
return true;
}
#endif
IRAmcorAc::IRAmcorAc(const uint16_t pin, const bool inverted,
const bool use_modulation)
: _irsend(pin, inverted, use_modulation) { this->stateReset(); }
void IRAmcorAc::begin(void) { _irsend.begin(); }
#if SEND_AMCOR
void IRAmcorAc::send(const uint16_t repeat) {
this->checksum(); // Create valid checksum before sending
_irsend.sendAmcor(remote_state, kAmcorStateLength, repeat);
}
#endif // SEND_AMCOR
uint8_t IRAmcorAc::calcChecksum(const uint8_t state[], const uint16_t length) {
return irutils::sumNibbles(state, length - 1);
}
bool IRAmcorAc::validChecksum(const uint8_t state[], const uint16_t length) {
return (state[length - 1] == IRAmcorAc::calcChecksum(state, length));
}
void IRAmcorAc::checksum(void) {
remote_state[kAmcorChecksumByte] = IRAmcorAc::calcChecksum(remote_state,
kAmcorStateLength);
}
void IRAmcorAc::stateReset(void) {
for (uint8_t i = 1; i < kAmcorStateLength; i++) remote_state[i] = 0x0;
remote_state[0] = 0x01;
setFan(kAmcorFanAuto);
setMode(kAmcorAuto);
setTemp(25); // 25C
}
uint8_t* IRAmcorAc::getRaw(void) {
this->checksum(); // Ensure correct bit array before returning
return remote_state;
}
void IRAmcorAc::setRaw(const uint8_t state[]) {
for (uint8_t i = 0; i < kAmcorStateLength; i++) remote_state[i] = state[i];
}
void IRAmcorAc::on(void) { setPower(true); }
void IRAmcorAc::off(void) { setPower(false); }
void IRAmcorAc::setPower(const bool on) {
remote_state[kAmcorPowerByte] &= ~kAmcorPowerMask;
remote_state[kAmcorPowerByte] |= (on ? kAmcorPowerOn : kAmcorPowerOff);
}
bool IRAmcorAc::getPower(void) {
return ((remote_state[kAmcorPowerByte] & kAmcorPowerMask) == kAmcorPowerOn);
}
// Set the temp in deg C
void IRAmcorAc::setTemp(const uint8_t degrees) {
uint8_t temp = std::max(kAmcorMinTemp, degrees);
temp = std::min(kAmcorMaxTemp, temp);
temp <<= 1;
remote_state[kAmcorTempByte] &= ~kAmcorTempMask;
remote_state[kAmcorTempByte] |= temp;
}
uint8_t IRAmcorAc::getTemp(void) {
return (remote_state[kAmcorTempByte] & kAmcorTempMask) >> 1;
}
// Maximum Cooling or Hearing
void IRAmcorAc::setMax(const bool on) {
if (on) {
switch (getMode()) {
case kAmcorCool:
setTemp(kAmcorMinTemp);
break;
case kAmcorHeat:
setTemp(kAmcorMaxTemp);
break;
default: // Not allowed in all other operating modes.
return;
}
remote_state[kAmcorSpecialByte] |= kAmcorMaxMask;
} else {
remote_state[kAmcorSpecialByte] &= ~kAmcorMaxMask;
}
}
bool IRAmcorAc::getMax(void) {
return ((remote_state[kAmcorSpecialByte] & kAmcorMaxMask) == kAmcorMaxMask);
}
// Set the speed of the fan
void IRAmcorAc::setFan(const uint8_t speed) {
switch (speed) {
case kAmcorFanAuto:
case kAmcorFanMin:
case kAmcorFanMed:
case kAmcorFanMax:
remote_state[kAmcorModeFanByte] &= ~kAmcorFanMask;
remote_state[kAmcorModeFanByte] |= speed << 4;
break;
default:
setFan(kAmcorFanAuto);
}
}
uint8_t IRAmcorAc::getFan(void) {
return (remote_state[kAmcorModeFanByte] & kAmcorFanMask) >> 4;
}
uint8_t IRAmcorAc::getMode(void) {
return remote_state[kAmcorModeFanByte] & kAmcorModeMask;
}
void IRAmcorAc::setMode(const uint8_t mode) {
remote_state[kAmcorSpecialByte] &= ~kAmcorVentMask; // Clear the vent setting
switch (mode) {
case kAmcorFan:
remote_state[kAmcorSpecialByte] |= kAmcorVentMask; // Set the vent option
// FALL-THRU
case kAmcorCool:
case kAmcorHeat:
case kAmcorDry:
case kAmcorAuto:
// Mask out bits
remote_state[kAmcorModeFanByte] &= ~kAmcorModeMask;
// Set the mode at bit positions
remote_state[kAmcorModeFanByte] |= mode;
return;
default:
this->setMode(kAmcorAuto);
}
}
// Convert a standard A/C mode into its native mode.
uint8_t IRAmcorAc::convertMode(const stdAc::opmode_t mode) {
switch (mode) {
case stdAc::opmode_t::kCool:
return kAmcorCool;
case stdAc::opmode_t::kHeat:
return kAmcorHeat;
case stdAc::opmode_t::kDry:
return kAmcorDry;
case stdAc::opmode_t::kFan:
return kAmcorFan;
default:
return kAmcorAuto;
}
}
// Convert a standard A/C Fan speed into its native fan speed.
uint8_t IRAmcorAc::convertFan(const stdAc::fanspeed_t speed) {
switch (speed) {
case stdAc::fanspeed_t::kMin:
case stdAc::fanspeed_t::kLow:
return kAmcorFanMin;
case stdAc::fanspeed_t::kMedium:
return kAmcorFanMed;
case stdAc::fanspeed_t::kHigh:
case stdAc::fanspeed_t::kMax:
return kAmcorFanMax;
default:
return kAmcorFanAuto;
}
}
// Convert a native mode to it's common equivalent.
stdAc::opmode_t IRAmcorAc::toCommonMode(const uint8_t mode) {
switch (mode) {
case kAmcorCool: return stdAc::opmode_t::kCool;
case kAmcorHeat: return stdAc::opmode_t::kHeat;
case kAmcorDry: return stdAc::opmode_t::kDry;
case kAmcorFan: return stdAc::opmode_t::kFan;
default: return stdAc::opmode_t::kAuto;
}
}
// Convert a native fan speed to it's common equivalent.
stdAc::fanspeed_t IRAmcorAc::toCommonFanSpeed(const uint8_t speed) {
switch (speed) {
case kAmcorFanMax: return stdAc::fanspeed_t::kMax;
case kAmcorFanMed: return stdAc::fanspeed_t::kMedium;
case kAmcorFanMin: return stdAc::fanspeed_t::kMin;
default: return stdAc::fanspeed_t::kAuto;
}
}
// Convert the A/C state to it's common equivalent.
stdAc::state_t IRAmcorAc::toCommon(void) {
stdAc::state_t result;
result.protocol = decode_type_t::AMCOR;
result.power = this->getPower();
result.mode = this->toCommonMode(this->getMode());
result.celsius = true;
result.degrees = this->getTemp();
result.fanspeed = this->toCommonFanSpeed(this->getFan());
// Not supported.
result.model = -1;
result.turbo = false;
result.swingv = stdAc::swingv_t::kOff;
result.swingh = stdAc::swingh_t::kOff;
result.light = false;
result.filter = false;
result.econo = false;
result.quiet = false;
result.clean = false;
result.beep = false;
result.sleep = -1;
result.clock = -1;
return result;
}
// Convert the internal state into a human readable string.
String IRAmcorAc::toString() {
String result = "";
result.reserve(70); // Reserve some heap for the string to reduce fragging.
result += addBoolToString(getPower(), F("Power"), false);
result += addModeToString(getMode(), kAmcorAuto, kAmcorCool,
kAmcorHeat, kAmcorDry, kAmcorFan);
result += addFanToString(getFan(), kAmcorFanMax, kAmcorFanMin,
kAmcorFanAuto, kAmcorFanAuto,
kAmcorFanMed);
result += addTempToString(getTemp());
result += addBoolToString(getMax(), F("Max"));
return result;
}
+118
View File
@@ -0,0 +1,118 @@
// Amcor A/C
//
// Copyright 2019 David Conran
#ifndef IR_AMCOR_H_
#define IR_AMCOR_H_
#define __STDC_LIMIT_MACROS
#include <stdint.h>
#ifndef UNIT_TEST
#include <Arduino.h>
#endif
#include "IRremoteESP8266.h"
#include "IRsend.h"
#ifdef UNIT_TEST
#include "IRsend_test.h"
#endif
// Supports:
// Brand: Amcor, Model: ADR-853H A/C
// Brand: Amcor, Model: TAC-495 remote
// Brand: Amcor, Model: TAC-444 remote
// Ref:
// https://github.com/crankyoldgit/IRremoteESP8266/issues/834
// Kudos:
// ldellus: For the breakdown and mapping of the bit values.
// Constants
// state[1]
const uint8_t kAmcorModeFanByte = 1;
// Fan Control
const uint8_t kAmcorFanMin = 0b001;
const uint8_t kAmcorFanMed = 0b010;
const uint8_t kAmcorFanMax = 0b011;
const uint8_t kAmcorFanAuto = 0b100;
const uint8_t kAmcorFanMask = 0b01110000;
// Modes
const uint8_t kAmcorCool = 0b001;
const uint8_t kAmcorHeat = 0b010;
const uint8_t kAmcorFan = 0b011; // Aka "Vent"
const uint8_t kAmcorDry = 0b100;
const uint8_t kAmcorAuto = 0b101;
const uint8_t kAmcorModeMask = 0b00000111;
// state[2]
const uint8_t kAmcorTempByte = 2;
// Temperature
const uint8_t kAmcorMinTemp = 12; // Celsius
const uint8_t kAmcorMaxTemp = 32; // Celsius
const uint8_t kAmcorTempMask = 0b01111110;
// state[5]
// Power
const uint8_t kAmcorPowerByte = 5;
const uint8_t kAmcorPowerMask = 0b11110000;
const uint8_t kAmcorPowerOn = 0b00110000; // 0x30
const uint8_t kAmcorPowerOff = 0b11000000; // 0xC0
// state[6]
const uint8_t kAmcorSpecialByte = 6;
// Max Mode (aka "Lo" in Cool and "Hi" in Heat)
const uint8_t kAmcorMaxMask = 0b00000011; // 0x03
// "Vent" Mode
const uint8_t kAmcorVentMask = 0b11000000; // 0xC0
// state[7]
// Checksum byte.
const uint8_t kAmcorChecksumByte = kAmcorStateLength - 1;
// Classes
class IRAmcorAc {
public:
explicit IRAmcorAc(const uint16_t pin, const bool inverted = false,
const bool use_modulation = true);
void stateReset();
#if SEND_AMCOR
void send(const uint16_t repeat = kAmcorDefaultRepeat);
uint8_t calibrate(void) { return _irsend.calibrate(); }
#endif // SEND_AMCOR
void begin();
static uint8_t calcChecksum(const uint8_t state[],
const uint16_t length = kAmcorStateLength);
static bool validChecksum(const uint8_t state[],
const uint16_t length = kAmcorStateLength);
void setPower(const bool state);
bool getPower();
void on();
void off();
void setTemp(const uint8_t temp);
uint8_t getTemp();
void setMax(const bool on);
bool getMax(void);
void setFan(const uint8_t speed);
uint8_t getFan();
void setMode(const uint8_t mode);
uint8_t getMode();
uint8_t* getRaw();
void setRaw(const uint8_t state[]);
uint8_t convertMode(const stdAc::opmode_t mode);
uint8_t convertFan(const stdAc::fanspeed_t speed);
static stdAc::opmode_t toCommonMode(const uint8_t mode);
static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed);
stdAc::state_t toCommon(void);
String toString();
#ifndef UNIT_TEST
private:
IRsend _irsend;
#else
IRsendTest _irsend;
#endif
uint8_t remote_state[kAmcorStateLength]; // The state of the IR remote.
void checksum(void);
};
#endif // IR_AMCOR_H_
+11 -3
View File
@@ -267,9 +267,6 @@ bool IRFujitsuAC::setRaw(const uint8_t newState[], const uint16_t length) {
return true;
}
// Set the requested power state of the A/C to off.
void IRFujitsuAC::off(void) { this->setCmd(kFujitsuAcCmdTurnOff); }
void IRFujitsuAC::stepHoriz(void) { this->setCmd(kFujitsuAcCmdStepHoriz); }
void IRFujitsuAC::toggleSwingHoriz(const bool update) {
@@ -336,6 +333,17 @@ uint8_t IRFujitsuAC::getCmd(const bool raw) {
return _cmd;
}
// Set the requested power state of the A/C.
void IRFujitsuAC::setPower(const bool on) {
this->setCmd(on ? kFujitsuAcCmdTurnOn : kFujitsuAcCmdTurnOff);
}
// Set the requested power state of the A/C to off.
void IRFujitsuAC::off(void) { this->setPower(false); }
// Set the requested power state of the A/C to on.
void IRFujitsuAC::on(void) { this->setPower(true); }
bool IRFujitsuAC::getPower(void) { return _cmd != kFujitsuAcCmdTurnOff; }
void IRFujitsuAC::setOutsideQuiet(const bool on) {
+3 -1
View File
@@ -104,7 +104,6 @@ class IRFujitsuAC {
uint8_t calibrate(void) { return _irsend.calibrate(); }
#endif // SEND_FUJITSU_AC
void begin(void);
void off(void);
void stepHoriz(void);
void toggleSwingHoriz(const bool update = true);
void stepVert(void);
@@ -123,6 +122,9 @@ class IRFujitsuAC {
bool setRaw(const uint8_t newState[], const uint16_t length);
uint8_t getStateLength(void);
static bool validChecksum(uint8_t* state, const uint16_t length);
void setPower(const bool on);
void off(void);
void on(void);
bool getPower(void);
void setOutsideQuiet(const bool on);
+47 -2
View File
@@ -35,6 +35,7 @@ using irutils::addLabeledString;
using irutils::addModeToString;
using irutils::addFanToString;
using irutils::addTempToString;
using irutils::minsToString;
#if SEND_GREE
// Send a Gree Heat Pump message.
@@ -222,12 +223,13 @@ void IRGreeAC::setTemp(const uint8_t temp) {
uint8_t new_temp = std::max((uint8_t)kGreeMinTemp, temp);
new_temp = std::min((uint8_t)kGreeMaxTemp, new_temp);
if (getMode() == kGreeAuto) new_temp = 25;
remote_state[1] = (remote_state[1] & 0xF0U) | (new_temp - kGreeMinTemp);
remote_state[1] = (remote_state[1] & ~kGreeTempMask) |
(new_temp - kGreeMinTemp);
}
// Return the set temp. in deg C
uint8_t IRGreeAC::getTemp(void) {
return ((remote_state[1] & 0xFU) + kGreeMinTemp);
return ((remote_state[1] & kGreeTempMask) + kGreeMinTemp);
}
// Set the speed of the fan, 0-3, 0 is auto, 1-3 is the speed
@@ -359,6 +361,44 @@ uint8_t IRGreeAC::getSwingVerticalPosition(void) {
return remote_state[4] & kGreeSwingPosMask;
}
void IRGreeAC::setTimerEnabled(const bool on) {
if (on)
remote_state[1] |= kGreeTimerEnabledBit;
else
remote_state[1] &= ~kGreeTimerEnabledBit;
}
bool IRGreeAC::getTimerEnabled(void) {
return remote_state[1] & kGreeTimerEnabledBit;
}
// Returns the number of minutes the timer is set for.
uint16_t IRGreeAC::getTimer(void) {
uint16_t hrs = irutils::bcdToUint8(
(remote_state[2] & kGreeTimerHoursMask) |
((remote_state[1] & kGreeTimerTensHrMask) >> 1));
return hrs * 60 + ((remote_state[1] & kGreeTimerHalfHrBit) ? 30 : 0);
}
// Set the A/C's timer to turn off in X many minutes.
// Stores time internally in 30 min units.
// e.g. 5 mins means 0 (& Off), 95 mins is 90 mins (& On). Max is 24 hours.
//
// Args:
// minutes: The number of minutes the timer should be set for.
void IRGreeAC::setTimer(const uint16_t minutes) {
// Clear the previous settings.
remote_state[1] &= ~kGreeTimer1Mask;
remote_state[2] &= ~kGreeTimerHoursMask;
uint16_t mins = std::min(kGreeTimerMax, minutes); // Bounds check.
setTimerEnabled(mins >= 30); // Timer is enabled when >= 30 mins.
uint8_t hours = mins / 60;
uint8_t halfhour = (mins % 60) < 30 ? 0 : 1;
// Set the "tens" digit of hours & the half hour.
remote_state[1] |= (((hours / 10) << 1) | halfhour) << 4;
// Set the "units" digit of hours.
remote_state[2] |= (hours % 10);
}
// Convert a standard A/C mode into its native mode.
uint8_t IRGreeAC::convertMode(const stdAc::opmode_t mode) {
@@ -504,6 +544,11 @@ String IRGreeAC::toString(void) {
result += F(" (Auto)");
break;
}
result += F(", Timer: ");
if (getTimerEnabled())
result += minsToString(getTimer());
else
result += F("Off");
return result;
}
+39 -27
View File
@@ -36,40 +36,48 @@ const uint8_t kGreeFan = 3;
const uint8_t kGreeHeat = 4;
// Byte 0
const uint8_t kGreeModeMask = 0b00000111;
const uint8_t kGreePower1Mask = 0b00001000;
const uint8_t kGreeFanMask = 0b00110000;
const uint8_t kGreeSwingAutoMask = 0b01000000;
const uint8_t kGreeSleepMask = 0b10000000;
// Byte 2
const uint8_t kGreeTurboMask = 0b00010000;
const uint8_t kGreeLightMask = 0b00100000;
const uint8_t kGreePower2Mask = 0b01000000; // This might not be used. See #814
const uint8_t kGreeXfanMask = 0b10000000;
// Byte 4
const uint8_t kGreeSwingPosMask = 0b00001111;
// byte 5
const uint8_t kGreeIFeelMask = 0b00000100;
const uint8_t kGreeWiFiMask = 0b01000000;
const uint8_t kGreeMinTemp = 16; // Celsius
const uint8_t kGreeMaxTemp = 30; // Celsius
const uint8_t kGreeModeMask = 0b00000111;
const uint8_t kGreePower1Mask = 0b00001000;
const uint8_t kGreeFanMask = 0b00110000;
const uint8_t kGreeFanAuto = 0;
const uint8_t kGreeFanMin = 1;
const uint8_t kGreeFanMed = 2;
const uint8_t kGreeFanMax = 3;
const uint8_t kGreeSwingAutoMask = 0b01000000;
const uint8_t kGreeSleepMask = 0b10000000;
// Byte 1
const uint8_t kGreeTempMask = 0b00001111;
const uint8_t kGreeMinTemp = 16; // Celsius
const uint8_t kGreeMaxTemp = 30; // Celsius
const uint8_t kGreeTimerEnabledBit = 0b10000000;
const uint8_t kGreeTimerHalfHrBit = 0b00010000;
const uint8_t kGreeTimerTensHrMask = 0b01100000;
const uint8_t kGreeTimer1Mask = kGreeTimerTensHrMask | kGreeTimerHalfHrBit;
const uint16_t kGreeTimerMax = 24 * 60;
const uint8_t kGreeSwingLastPos = 0b00000000;
const uint8_t kGreeSwingAuto = 0b00000001;
const uint8_t kGreeSwingUp = 0b00000010;
const uint8_t kGreeSwingMiddleUp = 0b00000011;
const uint8_t kGreeSwingMiddle = 0b00000100;
// Byte 2
const uint8_t kGreeTimerHoursMask = 0b00001111;
const uint8_t kGreeTurboMask = 0b00010000;
const uint8_t kGreeLightMask = 0b00100000;
// This might not be used. See #814
const uint8_t kGreePower2Mask = 0b01000000;
const uint8_t kGreeXfanMask = 0b10000000;
// Byte 4
const uint8_t kGreeSwingPosMask = 0b00001111;
// byte 5
const uint8_t kGreeIFeelMask = 0b00000100;
const uint8_t kGreeWiFiMask = 0b01000000;
const uint8_t kGreeSwingLastPos = 0b00000000;
const uint8_t kGreeSwingAuto = 0b00000001;
const uint8_t kGreeSwingUp = 0b00000010;
const uint8_t kGreeSwingMiddleUp = 0b00000011;
const uint8_t kGreeSwingMiddle = 0b00000100;
const uint8_t kGreeSwingMiddleDown = 0b00000101;
const uint8_t kGreeSwingDown = 0b00000110;
const uint8_t kGreeSwingDownAuto = 0b00000111;
const uint8_t kGreeSwingDown = 0b00000110;
const uint8_t kGreeSwingDownAuto = 0b00000111;
const uint8_t kGreeSwingMiddleAuto = 0b00001001;
const uint8_t kGreeSwingUpAuto = 0b00001011;
const uint8_t kGreeSwingUpAuto = 0b00001011;
// Legacy defines.
#define GREE_AUTO kGreeAuto
@@ -132,6 +140,8 @@ class IRGreeAC {
void setSwingVertical(const bool automatic, const uint8_t position);
bool getSwingVerticalAuto(void);
uint8_t getSwingVerticalPosition(void);
uint16_t getTimer(void);
void setTimer(const uint16_t minutes);
uint8_t convertMode(const stdAc::opmode_t mode);
uint8_t convertFan(const stdAc::fanspeed_t speed);
uint8_t convertSwingV(const stdAc::swingv_t swingv);
@@ -156,6 +166,8 @@ class IRGreeAC {
gree_ac_remote_model_t _model;
void checksum(const uint16_t length = kGreeStateLength);
void fixup(void);
void setTimerEnabled(const bool on);
bool getTimerEnabled(void);
};
#endif // IR_GREE_H_
+2 -8
View File
@@ -490,16 +490,10 @@ bool IRrecv::decodeKelvinator(decode_results *results, uint16_t nbits,
if (data_result.data != kKelvinatorCmdFooter) return false;
offset += data_result.used;
// Interdata gap.
if (!matchMark(results->rawbuf[offset++], kKelvinatorBitMark))
return false;
if (!matchSpace(results->rawbuf[offset++], kKelvinatorGapSpace))
return false;
// Data (Options) (32 bits)
// Gap + Data (Options) (32 bits)
used = matchGeneric(results->rawbuf + offset, results->state + pos,
results->rawlen - offset, 32,
0, 0,
kKelvinatorBitMark, kKelvinatorGapSpace,
kKelvinatorBitMark, kKelvinatorOneSpace,
kKelvinatorBitMark, kKelvinatorZeroSpace,
kKelvinatorBitMark, kKelvinatorGapSpace * 2,
+4
View File
@@ -9,6 +9,10 @@
#include <stdint.h>
#include "IRremoteESP8266.h"
// Supports:
// Brand: Yamaha, Model: RAV561 remote
// Brand: Yamaha, Model: RXV585B A/V Receiver
// Constants
// Ref:
// http://www.sbprojects.com/knowledge/ir/nec.php
+38 -8
View File
@@ -64,19 +64,18 @@ uint64_t IRTecoAc::getRaw(void) { return remote_state; }
void IRTecoAc::setRaw(const uint64_t new_code) { remote_state = new_code; }
void IRTecoAc::on(void) { remote_state |= kTecoPower; }
void IRTecoAc::on(void) { setPower(true); }
void IRTecoAc::off(void) { remote_state &= ~kTecoPower; }
void IRTecoAc::off(void) { setPower(false); }
void IRTecoAc::setPower(const bool on) {
if (on)
this->on();
remote_state |= kTecoPower;
else
this->off();
remote_state &= ~kTecoPower;
}
bool IRTecoAc::getPower(void) {
return (remote_state & kTecoPower) == kTecoPower; }
bool IRTecoAc::getPower(void) { return remote_state & kTecoPower; }
void IRTecoAc::setTemp(const uint8_t temp) {
uint8_t newtemp = temp;
@@ -146,6 +145,33 @@ void IRTecoAc::setSleep(const bool on) {
bool IRTecoAc::getSleep(void) { return remote_state & kTecoSleep; }
bool IRTecoAc::getLight(void) { return remote_state & kTecoLight; }
void IRTecoAc::setLight(const bool on) {
if (on)
remote_state |= kTecoLight;
else
remote_state &= ~kTecoLight;
}
bool IRTecoAc::getHumid(void) { return remote_state & kTecoHumid; }
void IRTecoAc::setHumid(const bool on) {
if (on)
remote_state |= kTecoHumid;
else
remote_state &= ~kTecoHumid;
}
bool IRTecoAc::getSave(void) { return remote_state & kTecoSave; }
void IRTecoAc::setSave(const bool on) {
if (on)
remote_state |= kTecoSave;
else
remote_state &= ~kTecoSave;
}
// Convert a standard A/C mode into its native mode.
uint8_t IRTecoAc::convertMode(const stdAc::opmode_t mode) {
switch (mode) {
@@ -212,10 +238,10 @@ stdAc::state_t IRTecoAc::toCommon(void) {
result.swingv = this->getSwing() ? stdAc::swingv_t::kAuto :
stdAc::swingv_t::kOff;
result.sleep = this->getSleep() ? 0 : -1;
result.light = this->getLight();
// Not supported.
result.swingh = stdAc::swingh_t::kOff;
result.turbo = false;
result.light = false;
result.filter = false;
result.econo = false;
result.quiet = false;
@@ -228,7 +254,7 @@ stdAc::state_t IRTecoAc::toCommon(void) {
// Convert the internal state into a human readable string.
String IRTecoAc::toString(void) {
String result = "";
result.reserve(80); // Reserve some heap for the string to reduce fragging.
result.reserve(100); // Reserve some heap for the string to reduce fragging.
result += addBoolToString(getPower(), F("Power"), false);
result += addModeToString(getMode(), kTecoAuto, kTecoCool, kTecoHeat,
kTecoDry, kTecoFan);
@@ -237,6 +263,10 @@ String IRTecoAc::toString(void) {
kTecoFanAuto, kTecoFanAuto, kTecoFanMed);
result += addBoolToString(getSleep(), F("Sleep"));
result += addBoolToString(getSwing(), F("Swing"));
result += addBoolToString(getLight(), F("Light"));
result += addBoolToString(getHumid(), F("Humid"));
result += addBoolToString(getSave(), F("Save"));
return result;
}
+23 -3
View File
@@ -12,6 +12,10 @@
#include "IRsend_test.h"
#endif
// Supports:
// Brand: Alaska, Model: SAC9010QC A/C
// Brand: Alaska, Model: SAC9010QC remote
// Constants. Using LSB to be able to send only 35bits.
const uint8_t kTecoAuto = 0; // 0b000
const uint8_t kTecoCool = 1; // 0b001
@@ -35,6 +39,9 @@ const uint64_t kTecoTimerHalfH = 0b00000000000000000000001000000000000;
const uint64_t kTecoTimerTenHr = 0b00000000000000000000110000000000000;
const uint64_t kTecoTimerOn = 0b00000000000000000001000000000000000;
const uint64_t kTecoTimerUniHr = 0b00000000000000011110000000000000000;
const uint64_t kTecoHumid = 0b00000000000000100000000000000000000;
const uint64_t kTecoLight = 0b00000000000001000000000000000000000;
const uint64_t kTecoSave = 0b00000000000100000000000000000000000;
const uint64_t kTecoReset = 0b01001010000000000000010000000000000;
/*
(header mark and space)
@@ -42,8 +49,12 @@ const uint64_t kTecoReset = 0b01001010000000000000010000000000000;
byte 0 = Cst 0x02
byte 1 = Cst 0x50
b6-7 = "AIR" 0, 1, 2 (Not Implemented)
byte 2:
b0-3 = 0b0000
b0 = Save
b1 = "Tree with bubbles" / Filter?? (Not Implemented)
b2 = Light/LED.
b3 = Humid
b4-7 = Timer hours (unit, not thenth)
hours:
0000 (0) = +0 hour
@@ -110,12 +121,21 @@ class IRTecoAc {
void setMode(const uint8_t mode);
uint8_t getMode(void);
void setSwing(const bool state);
void setSwing(const bool on);
bool getSwing(void);
void setSleep(const bool state);
void setSleep(const bool on);
bool getSleep(void);
void setLight(const bool on);
bool getLight(void);
void setHumid(const bool on);
bool getHumid(void);
void setSave(const bool on);
bool getSave(void);
// void setTimer(uint8_t time); // To check unit
// uint8_t getTimer(uint8_t);
+26 -2
View File
@@ -1,6 +1,7 @@
// Copyright 2019 David Conran
#include <string>
#include "ir_Amcor.h"
#include "ir_Argo.h"
#include "ir_Daikin.h"
#include "ir_Electra.h"
@@ -33,6 +34,27 @@
// Tests for IRac class.
TEST(TestIRac, Amcor) {
IRAmcorAc ac(0);
IRac irac(0);
IRrecv capture(0);
char expected[] =
"Power: On, Mode: 5 (AUTO), Fan: 3 (High), Temp: 19C, Max: Off";
ac.begin();
irac.amcor(&ac,
true, // Power
stdAc::opmode_t::kAuto, // Mode
19, // Celsius
stdAc::fanspeed_t::kHigh); // Fan speed
ASSERT_EQ(expected, ac.toString());
ac._irsend.makeDecodeResult();
EXPECT_TRUE(capture.decode(&ac._irsend.capture));
ASSERT_EQ(AMCOR, ac._irsend.capture.decode_type);
ASSERT_EQ(kAmcorBits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
}
TEST(TestIRac, Argo) {
IRArgoAC ac(0);
IRac irac(0);
@@ -390,7 +412,7 @@ TEST(TestIRac, Gree) {
"Model: 1 (YAW1F), Power: On, Mode: 1 (COOL), Temp: 22C, "
"Fan: 2 (Medium), Turbo: Off, IFeel: Off, WiFi: Off, XFan: On, "
"Light: On, Sleep: On, Swing Vertical Mode: Manual, "
"Swing Vertical Pos: 3";
"Swing Vertical Pos: 3, Timer: Off";
ac.begin();
irac.gree(&ac,
@@ -822,7 +844,7 @@ TEST(TestIRac, Teco) {
IRrecv capture(0);
char expected[] =
"Power: On, Mode: 0 (AUTO), Temp: 21C, Fan: 2 (Medium), Sleep: On, "
"Swing: On";
"Swing: On, Light: On, Humid: Off, Save: Off";
ac.begin();
irac.teco(&ac,
@@ -831,6 +853,7 @@ TEST(TestIRac, Teco) {
21, // Celsius
stdAc::fanspeed_t::kMedium, // Fan speed
stdAc::swingv_t::kAuto, // Veritcal swing
true, // Light
8 * 60 + 30); // Sleep
ASSERT_EQ(expected, ac.toString());
ac._irsend.makeDecodeResult();
@@ -1220,6 +1243,7 @@ TEST(TestIRac, swinghToString) {
EXPECT_EQ("off", IRac::swinghToString(stdAc::swingh_t::kOff));
EXPECT_EQ("left", IRac::swinghToString(stdAc::swingh_t::kLeft));
EXPECT_EQ("auto", IRac::swinghToString(stdAc::swingh_t::kAuto));
EXPECT_EQ("wide", IRac::swinghToString(stdAc::swingh_t::kWide));
EXPECT_EQ("unknown", IRac::swinghToString((stdAc::swingh_t)500));
}
+3 -2
View File
@@ -88,7 +88,8 @@ PROTOCOLS = ir_NEC.o ir_Sony.o ir_Samsung.o ir_JVC.o ir_RCMM.o ir_RC5_RC6.o \
ir_Amcor.o
# All the IR Protocol header files.
PROTOCOLS_H = $(USER_DIR)/ir_Argo.h \
PROTOCOLS_H = $(USER_DIR)/ir_Amcor.h \
$(USER_DIR)/ir_Argo.h \
$(USER_DIR)/ir_Gree.h \
$(USER_DIR)/ir_Magiquest.h \
$(USER_DIR)/ir_Coolix.h \
@@ -609,7 +610,7 @@ ir_Neoclima_test.o : ir_Neoclima_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
ir_Neoclima_test : $(COMMON_OBJ) ir_Neoclima_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Amcor.o : $(USER_DIR)/ir_Amcor.cpp $(COMMON_DEPS)
ir_Amcor.o : $(USER_DIR)/ir_Amcor.h $(USER_DIR)/ir_Amcor.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Amcor.cpp
ir_Amcor_test.o : ir_Amcor_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
+201 -4
View File
@@ -1,6 +1,7 @@
// Copyright 2018 David Conran
// Copyright 2019 David Conran
#include "IRac.h"
#include "ir_Amcor.h"
#include "IRrecv.h"
#include "IRrecv_test.h"
#include "IRsend.h"
@@ -12,10 +13,9 @@ TEST(TestUtils, Housekeeping) {
ASSERT_EQ("AMCOR", typeToString(decode_type_t::AMCOR));
ASSERT_EQ(decode_type_t::AMCOR, strToDecodeType("AMCOR"));
ASSERT_TRUE(hasACState(decode_type_t::AMCOR));
ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::AMCOR));
ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::AMCOR));
}
// Test sending typical data only.
TEST(TestSendAmcor, SendDataOnly) {
IRsendTest irsend(0);
@@ -54,6 +54,7 @@ TEST(TestSendAmcor, SendDataOnly) {
TEST(TestDecodeAmcor, SyntheticSelfDecode) {
IRsendTest irsend(0);
IRrecv irrecv(0);
IRAmcorAc ac(0);
uint8_t expectedState[kAmcorStateLength] = {
0x01, 0x41, 0x30, 0x00, 0x00, 0x30, 0x00, 0x0C};
@@ -65,8 +66,11 @@ TEST(TestDecodeAmcor, SyntheticSelfDecode) {
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(AMCOR, irsend.capture.decode_type);
EXPECT_EQ(kAmcorBits, irsend.capture.bits);
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
ac.setRaw(irsend.capture.state);
EXPECT_EQ(
"Power: On, Mode: 1 (COOL), Fan: 4 (Auto), Temp: 24C, Max: Off",
ac.toString());
}
TEST(TestDecodeAmcor, RealExample) {
@@ -152,3 +156,196 @@ TEST(TestDecodeAmcor, RealExample) {
EXPECT_EQ(kAmcorBits, irsend.capture.bits);
EXPECT_STATE_EQ(expectedState2, irsend.capture.state, irsend.capture.bits);
}
// Tests for IRAmcorAc class.
TEST(TestAmcorAcClass, Power) {
IRAmcorAc ac(0);
ac.begin();
ac.on();
EXPECT_TRUE(ac.getPower());
ac.off();
EXPECT_FALSE(ac.getPower());
ac.setPower(true);
EXPECT_TRUE(ac.getPower());
ac.setPower(false);
EXPECT_FALSE(ac.getPower());
}
TEST(TestAmcorAcClass, Temperature) {
IRAmcorAc ac(0);
ac.begin();
ac.setTemp(0);
EXPECT_EQ(kAmcorMinTemp, ac.getTemp());
ac.setTemp(255);
EXPECT_EQ(kAmcorMaxTemp, ac.getTemp());
ac.setTemp(kAmcorMinTemp);
EXPECT_EQ(kAmcorMinTemp, ac.getTemp());
ac.setTemp(kAmcorMaxTemp);
EXPECT_EQ(kAmcorMaxTemp, ac.getTemp());
ac.setTemp(kAmcorMinTemp - 1);
EXPECT_EQ(kAmcorMinTemp, ac.getTemp());
ac.setTemp(kAmcorMaxTemp + 1);
EXPECT_EQ(kAmcorMaxTemp, ac.getTemp());
ac.setTemp(17);
EXPECT_EQ(17, ac.getTemp());
ac.setTemp(21);
EXPECT_EQ(21, ac.getTemp());
ac.setTemp(25);
EXPECT_EQ(25, ac.getTemp());
ac.setTemp(29);
EXPECT_EQ(29, ac.getTemp());
}
TEST(TestAmcorAcClass, OperatingMode) {
IRAmcorAc ac(0);
ac.begin();
ac.setMode(kAmcorAuto);
EXPECT_EQ(kAmcorAuto, ac.getMode());
ac.setMode(kAmcorCool);
EXPECT_EQ(kAmcorCool, ac.getMode());
ac.setMode(kAmcorHeat);
EXPECT_EQ(kAmcorHeat, ac.getMode());
ac.setMode(kAmcorDry);
EXPECT_EQ(kAmcorDry, ac.getMode());
ac.setMode(kAmcorFan);
EXPECT_EQ(kAmcorFan, ac.getMode());
ac.setMode(kAmcorAuto + 1);
EXPECT_EQ(kAmcorAuto, ac.getMode());
ac.setMode(255);
EXPECT_EQ(kAmcorAuto, ac.getMode());
}
TEST(TestAmcorAcClass, FanSpeed) {
IRAmcorAc ac(0);
ac.begin();
ac.setFan(0);
EXPECT_EQ(kAmcorFanAuto, ac.getFan());
ac.setFan(255);
EXPECT_EQ(kAmcorFanAuto, ac.getFan());
ac.setFan(kAmcorFanMax);
EXPECT_EQ(kAmcorFanMax, ac.getFan());
ac.setFan(kAmcorFanMax + 1);
EXPECT_EQ(kAmcorFanAuto, ac.getFan());
ac.setFan(kAmcorFanMax - 1);
EXPECT_EQ(kAmcorFanMax - 1, ac.getFan());
ac.setFan(1);
EXPECT_EQ(1, ac.getFan());
ac.setFan(1);
EXPECT_EQ(1, ac.getFan());
ac.setFan(3);
EXPECT_EQ(3, ac.getFan());
}
TEST(TestAmcorAcClass, Checksums) {
uint8_t state[kAmcorStateLength] = {
0x01, 0x41, 0x30, 0x00, 0x00, 0x30, 0x00, 0x0C};
ASSERT_EQ(0x0C, IRAmcorAc::calcChecksum(state));
EXPECT_TRUE(IRAmcorAc::validChecksum(state));
// Change the array so the checksum is invalid.
state[0] ^= 0xFF;
EXPECT_FALSE(IRAmcorAc::validChecksum(state));
// Restore the previous change, and change another byte.
state[0] ^= 0xFF;
state[4] ^= 0xFF;
EXPECT_FALSE(IRAmcorAc::validChecksum(state));
state[4] ^= 0xFF;
EXPECT_TRUE(IRAmcorAc::validChecksum(state));
// Additional known good states.
uint8_t knownGood1[kAmcorStateLength] = {
0x01, 0x11, 0x3E, 0x00, 0x00, 0x30, 0x00, 0x17};
EXPECT_TRUE(IRAmcorAc::validChecksum(knownGood1));
ASSERT_EQ(0x17, IRAmcorAc::calcChecksum(knownGood1));
uint8_t knownGood2[kAmcorStateLength] = {
0x01, 0x22, 0x26, 0x00, 0x00, 0x30, 0x00, 0x10};
EXPECT_TRUE(IRAmcorAc::validChecksum(knownGood2));
ASSERT_EQ(0x10, IRAmcorAc::calcChecksum(knownGood2));
uint8_t knownGood3[kAmcorStateLength] = {
0x01, 0x41, 0x24, 0x00, 0x00, 0xC0, 0x00, 0x18};
EXPECT_TRUE(IRAmcorAc::validChecksum(knownGood3));
ASSERT_EQ(0x18, IRAmcorAc::calcChecksum(knownGood3));
// For a recalculation.
uint8_t knownBad[kAmcorStateLength] = {
// Same as knownGood3 except for the checksum.
0x01, 0x41, 0x24, 0x00, 0x00, 0xC0, 0x00, 0x00};
EXPECT_FALSE(IRAmcorAc::validChecksum(knownBad));
IRAmcorAc ac(0);
ac.setRaw(knownBad);
EXPECT_STATE_EQ(knownGood3, ac.getRaw(), kAmcorBits);
}
TEST(TestAmcorAcClass, Max) {
IRAmcorAc ac(0);
ac.begin();
ac.setMode(kAmcorCool);
ac.setMax(true);
EXPECT_EQ(kAmcorCool, ac.getMode());
EXPECT_EQ(kAmcorMinTemp, ac.getTemp());
EXPECT_TRUE(ac.getMax());
ac.setMax(false);
EXPECT_EQ(kAmcorCool, ac.getMode());
EXPECT_EQ(kAmcorMinTemp, ac.getTemp());
EXPECT_FALSE(ac.getMax());
ac.setMode(kAmcorHeat);
ac.setMax(true);
EXPECT_EQ(kAmcorHeat, ac.getMode());
EXPECT_EQ(kAmcorMaxTemp, ac.getTemp());
EXPECT_TRUE(ac.getMax());
ac.setMax(false);
EXPECT_EQ(kAmcorHeat, ac.getMode());
EXPECT_EQ(kAmcorMaxTemp, ac.getTemp());
EXPECT_FALSE(ac.getMax());
ac.setMode(kAmcorAuto);
ac.setTemp(25);
ac.setMax(true);
EXPECT_EQ(kAmcorAuto, ac.getMode());
EXPECT_EQ(25, ac.getTemp());
EXPECT_FALSE(ac.getMax());
// Test known real data.
uint8_t lo[kAmcorStateLength] = {
0x01, 0x41, 0x18, 0x00, 0x00, 0x30, 0x03, 0x15};
uint8_t hi[kAmcorStateLength] = {
0x01, 0x12, 0x40, 0x00, 0x00, 0x30, 0x03, 0x0E};
ac.setRaw(lo);
EXPECT_EQ("Power: On, Mode: 1 (COOL), Fan: 4 (Auto), Temp: 12C, Max: On",
ac.toString());
ac.setRaw(hi);
EXPECT_EQ("Power: On, Mode: 2 (HEAT), Fan: 1 (Low), Temp: 32C, Max: On",
ac.toString());
}
+47 -4
View File
@@ -497,7 +497,8 @@ TEST(TestGreeClass, HumanReadable) {
EXPECT_EQ(
"Model: 1 (YAW1F), Power: Off, Mode: 0 (AUTO), Temp: 25C, Fan: 0 (Auto), "
"Turbo: Off, IFeel: Off, WiFi: Off, XFan: Off, Light: On, Sleep: Off, "
"Swing Vertical Mode: Manual, Swing Vertical Pos: 0 (Last Pos)",
"Swing Vertical Mode: Manual, Swing Vertical Pos: 0 (Last Pos), "
"Timer: Off",
irgree.toString());
irgree.on();
irgree.setMode(kGreeCool);
@@ -510,10 +511,11 @@ TEST(TestGreeClass, HumanReadable) {
irgree.setIFeel(true);
irgree.setWiFi(true);
irgree.setSwingVertical(true, kGreeSwingAuto);
irgree.setTimer(12 * 60 + 30);
EXPECT_EQ(
"Model: 1 (YAW1F), Power: On, Mode: 1 (COOL), Temp: 16C, Fan: 3 (High), "
"Turbo: On, IFeel: On, WiFi: On, XFan: On, Light: Off, Sleep: On, "
"Swing Vertical Mode: Auto, Swing Vertical Pos: 1 (Auto)",
"Swing Vertical Mode: Auto, Swing Vertical Pos: 1 (Auto), Timer: 12:30",
irgree.toString());
}
@@ -573,7 +575,7 @@ TEST(TestDecodeGree, NormalRealExample) {
EXPECT_EQ(
"Model: 1 (YAW1F), Power: On, Mode: 1 (COOL), Temp: 26C, Fan: 1 (Low), "
"Turbo: Off, IFeel: Off, WiFi: Off, XFan: Off, Light: On, Sleep: Off, "
"Swing Vertical Mode: Manual, Swing Vertical Pos: 2",
"Swing Vertical Mode: Manual, Swing Vertical Pos: 2, Timer: Off",
irgree.toString());
}
@@ -628,7 +630,7 @@ TEST(TestGreeClass, Issue814Power) {
EXPECT_EQ(
"Model: 2 (YBOFB), Power: On, Mode: 1 (COOL), Temp: 23C, Fan: 1 (Low), "
"Turbo: Off, IFeel: Off, WiFi: Off, XFan: Off, Light: On, Sleep: Off, "
"Swing Vertical Mode: Auto, Swing Vertical Pos: 1 (Auto)",
"Swing Vertical Mode: Auto, Swing Vertical Pos: 1 (Auto), Timer: Off",
ac.toString());
ac.off();
EXPECT_STATE_EQ(off, ac.getRaw(), kGreeBits);
@@ -643,3 +645,44 @@ TEST(TestGreeClass, Issue814Power) {
ac.on();
EXPECT_STATE_EQ(YBOFB_on, ac.getRaw(), kGreeBits);
}
TEST(TestGreeClass, Timer) {
IRGreeAC ac(0);
ac.begin();
ac.setTimer(0);
EXPECT_FALSE(ac.getTimerEnabled());
EXPECT_EQ(0, ac.getTimer());
ac.setTimer(29);
EXPECT_FALSE(ac.getTimerEnabled());
EXPECT_EQ(0, ac.getTimer());
ac.setTimer(30);
EXPECT_TRUE(ac.getTimerEnabled());
EXPECT_EQ(30, ac.getTimer());
ac.setTimer(60);
EXPECT_TRUE(ac.getTimerEnabled());
EXPECT_EQ(60, ac.getTimer());
ac.setTimer(90);
EXPECT_TRUE(ac.getTimerEnabled());
EXPECT_EQ(90, ac.getTimer());
ac.setTimer(10 * 60);
EXPECT_TRUE(ac.getTimerEnabled());
EXPECT_EQ(10 * 60, ac.getTimer());
ac.setTimer(23 * 60 + 59);
EXPECT_TRUE(ac.getTimerEnabled());
EXPECT_EQ(23 * 60 + 30, ac.getTimer());
ac.setTimer(24 * 60 + 1);
EXPECT_TRUE(ac.getTimerEnabled());
EXPECT_EQ(24 * 60, ac.getTimer());
ac.setTimer(24 * 60 + 30);
EXPECT_TRUE(ac.getTimerEnabled());
EXPECT_EQ(24 * 60, ac.getTimer());
}
+59 -10
View File
@@ -198,26 +198,72 @@ TEST(TestTecoACClass, Sleep) {
EXPECT_TRUE(ac.getSleep());
}
TEST(TestTecoACClass, Light) {
IRTecoAc ac(0);
ac.begin();
ac.setLight(true);
EXPECT_TRUE(ac.getLight());
ac.setLight(false);
EXPECT_EQ(false, ac.getLight());
ac.setLight(true);
EXPECT_TRUE(ac.getLight());
// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/870#issue-484797174
ac.setRaw(0x250200A09);
EXPECT_TRUE(ac.getLight());
}
TEST(TestTecoACClass, Humid) {
IRTecoAc ac(0);
ac.begin();
ac.setHumid(true);
EXPECT_TRUE(ac.getHumid());
ac.setHumid(false);
EXPECT_EQ(false, ac.getHumid());
ac.setHumid(true);
EXPECT_TRUE(ac.getHumid());
// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/870#issuecomment-524536810
ac.setRaw(0x250100A09);
EXPECT_TRUE(ac.getHumid());
}
TEST(TestTecoACClass, Save) {
IRTecoAc ac(0);
ac.begin();
ac.setSave(true);
EXPECT_TRUE(ac.getSave());
ac.setSave(false);
EXPECT_EQ(false, ac.getSave());
ac.setSave(true);
EXPECT_TRUE(ac.getSave());
// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/870#issuecomment-524536810
ac.setRaw(0x250800A09);
EXPECT_TRUE(ac.getSave());
}
TEST(TestTecoACClass, MessageConstuction) {
IRTecoAc ac(0);
EXPECT_EQ(
"Power: Off, Mode: 0 (AUTO), Temp: 16C, Fan: 0 (Auto), Sleep: Off, "
"Swing: Off",
"Swing: Off, Light: Off, Humid: Off, Save: Off",
ac.toString());
ac.setPower(true);
ac.setMode(kTecoCool);
ac.setTemp(21);
ac.setFan(kTecoFanHigh);
ac.setSwing(false);
ac.setLight(false);
EXPECT_EQ(
"Power: On, Mode: 1 (COOL), Temp: 21C, Fan: 3 (High), Sleep: Off, "
"Swing: Off",
"Swing: Off, Light: Off, Humid: Off, Save: Off",
ac.toString());
ac.setSwing(true);
EXPECT_EQ(
"Power: On, Mode: 1 (COOL), Temp: 21C, Fan: 3 (High), Sleep: Off, "
"Swing: On",
"Swing: On, Light: Off, Humid: Off, Save: Off",
ac.toString());
ac.setSwing(false);
ac.setFan(kTecoFanLow);
@@ -225,17 +271,20 @@ TEST(TestTecoACClass, MessageConstuction) {
ac.setMode(kTecoHeat);
EXPECT_EQ(
"Power: On, Mode: 4 (HEAT), Temp: 21C, Fan: 1 (Low), Sleep: On, "
"Swing: Off",
"Swing: Off, Light: Off, Humid: Off, Save: Off",
ac.toString());
ac.setSleep(false);
EXPECT_EQ(
"Power: On, Mode: 4 (HEAT), Temp: 21C, Fan: 1 (Low), Sleep: Off, "
"Swing: Off",
"Swing: Off, Light: Off, Humid: Off, Save: Off",
ac.toString());
ac.setTemp(25);
ac.setLight(true);
ac.setSave(true);
ac.setHumid(true);
EXPECT_EQ(
"Power: On, Mode: 4 (HEAT), Temp: 25C, Fan: 1 (Low), Sleep: Off, "
"Swing: Off",
"Swing: Off, Light: On, Humid: On, Save: On",
ac.toString());
}
@@ -253,7 +302,7 @@ TEST(TestTecoACClass, ReconstructKnownMessage) {
EXPECT_EQ(expected, ac.getRaw());
EXPECT_EQ(
"Power: On, Mode: 1 (COOL), Temp: 27C, Fan: 0 (Auto), Sleep: On, "
"Swing: On",
"Swing: On, Light: Off, Humid: Off, Save: Off",
ac.toString());
}
@@ -295,7 +344,7 @@ TEST(TestDecodeTeco, NormalDecodeWithStrict) {
ac.setRaw(irsend.capture.value);
EXPECT_EQ(
"Power: Off, Mode: 0 (AUTO), Temp: 16C, Fan: 0 (Auto), Sleep: Off, "
"Swing: Off",
"Swing: Off, Light: Off, Humid: Off, Save: Off",
ac.toString());
}
@@ -328,7 +377,7 @@ TEST(TestDecodeTeco, RealNormalExample) {
ac.setRaw(irsend.capture.value);
EXPECT_EQ(
"Power: On, Mode: 1 (COOL), Temp: 27C, Fan: 0 (Auto), Sleep: On, "
"Swing: On",
"Swing: On, Light: Off, Humid: Off, Save: Off",
ac.toString());
uint16_t rawData2[73] = {
@@ -353,7 +402,7 @@ TEST(TestDecodeTeco, RealNormalExample) {
ac.setRaw(irsend.capture.value);
EXPECT_EQ(
"Power: On, Mode: 2 (DRY), Temp: 21C, Fan: 2 (Medium), Sleep: Off, "
"Swing: On",
"Swing: On, Light: Off, Humid: Off, Save: Off",
ac.toString());
}
+2 -2
View File
@@ -228,5 +228,5 @@ ir_Goodweather.o : $(USER_DIR)/ir_Goodweather.cpp $(USER_DIR)/ir_Goodweather.h $
ir_Neoclima.o : $(USER_DIR)/ir_Neoclima.cpp $(USER_DIR)/ir_Neoclima.h $(COMMON_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Neoclima.cpp
ir_Amcor.o : $(USER_DIR)/ir_Amcor.cpp $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Amcor.cpp
ir_Amcor.o : $(USER_DIR)/ir_Amcor.cpp $(USER_DIR)/ir_Amcor.h $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Amcor.cpp
+9 -5
View File
@@ -12,10 +12,11 @@
//---IRSEND: That commands format is: IRSEND,<protocol>,<data>,<bits>,<repeat>
// bits and repeat default to 0 if not used and they are optional
// For protocols RAW and RAW2 there is no bits and repeat part, they are supposed to be replayed as they are calculated by a Google docs sheet or by plugin P016
//---IRSENDAC: That commands format is: IRSENDAC,{"Protocol":"COOLIX","Power":"on","Opmode":"dry","Fanspeed":"auto","Degrees":22,"Swingv":"max","Swingh":"off"}
//---IRSENDAC: That commands format is: IRSENDAC,{"protocol":"COOLIX","power":"on","opmode":"dry","fanspeed":"auto","degrees":22,"swingv":"max","swingh":"off"}
//--- The JSON keys are case sensitive and allways small case. The JSON data are case insensitive
// The possible values
// Protocols: Argo Coolix Daikin Fujitsu Haier Hitachi Kelvinator Midea Mitsubishi MitsubishiHeavy Panasonic Samsung Sharp Tcl Teco Toshiba Trotec Vestel Whirlpool
//---Opmodes: ---Fanspeed: --Swingv: --Swingh:
//---opmodes: ---fanspeed: --swingv: --swingh:
// - "off" - "auto" - "off" - "off"
// - "auto" - "min" - "auto" - "auto"
// - "cool" - "low" - "highest" - "leftmax"
@@ -23,11 +24,14 @@
// - "dry" - "high" - "middle" - "middle"
// - "fan_only" - "max" - "low" - "right"
// - "lowest" - "rightmax"
// - "wide"
// "on" - "off" parameters are:
// - "Power" - "Celsius" - "Quiet" - "Turbo" - "Econo" - "Light" - "Filter" - "Clean" - "Light" - "Beep"
// - "power" - "celsius" - "quiet" - "turbo" - "econo" - "light" - "filter" - "clean" - "light" - "beep"
// If celcius is set to "off" then farenheit will be used
// - "Sleep" Nr. of mins of sleep mode, or use sleep mode. (<= 0 means off.)
// - "Clock" Nr. of mins past midnight to set the clock to. (< 0 means off.)
// - "sleep" Nr. of mins of sleep mode, or use sleep mode. (<= 0 means off.)
// - "clock" Nr. of mins past midnight to set the clock to. (< 0 means off.)
// - "model" . Nr or string representation of the model. Better to find it throught P016 - IR RX (0 means default.)
#include <IRremoteESP8266.h>
#include <IRac.h>
#include <IRutils.h>