Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
Initial commit of arduino mitsubishi package HeatPump
  • Loading branch information
SwiCago committed Jan 8, 2017
0 parents commit 954aff2
Show file tree
Hide file tree
Showing 5 changed files with 362 additions and 0 deletions.
127 changes: 127 additions & 0 deletions examples/HP_cntrl_esp8266/HP_cntrl_esp8266.ino
@@ -0,0 +1,127 @@
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <DNSServer.h>
#include <HeatPump.h>

const char* ssid = "esp8266";

const char* html = "<html>\n<head>\n<meta name='viewport' content='width=device-width, initial-scale=2'/>\n"
"<style></style>\n"
"<body><h3>Heat Pump Demo</h3>\n<form>\n<table>\n"
"<tr>\n<td>Power:</td>\n<td>\n_POWER_</td>\n</tr>\n"
"<tr>\n<td>Mode:</td>\n<td>\n_MODE_</td>\n</tr>\n"
"<tr>\n<td>Temp:</td>\n<td>\n_TEMP_</td>\n</tr>"
"<tr>\n<td>Fan:</td>\n<td>\n_FAN_</td>\n</tr>\n"
"<tr>\n<td>Vane:</td><td>\n_VANE_</td>\n</tr>\n"
"<tr>\n<td>Direction:</td>\n<td>\n_DIR_</td>\n</tr>\n"
"</table>\n<br/><input type='submit' value='Change Settings'/>\n</form><br/><br/>"
"<form><input type='submit' name='CONNECT' value='Re-Connect'/>\n</form>\n"
"</body>\n</html>\n";

const byte DNS_PORT = 53;
IPAddress apIP(192, 168, 1, 1);
IPAddress netMsk(255, 255, 255, 0);
DNSServer dnsServer;
ESP8266WebServer server(80);

HeatPump hp;
String wantedSettings[6] = {};

void setup() {
hp.connect(&Serial);
hp.getSettings(wantedSettings);
WiFi.mode(WIFI_AP);
WiFi.softAPConfig(apIP, apIP, netMsk);
WiFi.softAP(ssid);//, password);
dnsServer.setErrorReplyCode(DNSReplyCode::NoError);
dnsServer.start(DNS_PORT, "*", apIP);
server.on("/", handle_root);
server.on("/generate_204", handle_root);
server.onNotFound(handleNotFound);
server.begin();
}

void loop() {
dnsServer.processNextRequest();
server.handleClient();
}

String encodeString(String toEncode) {
toEncode.replace("<", "&lt;");
toEncode.replace(">", "&gt;");
toEncode.replace("|", "&vert;");
return toEncode;
}

String createOptionSelector(String name, const String values[], int len, String value) {
String str = "<select name='" + name + "'>\n";
for (int i = 0; i < len; i++) {
String encoded = encodeString(values[i]);
str += "<option value='";
str += String(i);
str += "'";
str += values[i] == value ? " selected" : "";
str += ">";
str += encoded;
str += "</option>\n";
}
str += "</select>\n";
return str;
}

void handleNotFound() {
server.send ( 200, "text/plain", "URI Not Found" );
}

void handle_root() {
change_states();
String toSend = html;
toSend.replace("_POWER_", createOptionSelector("POWER", hp.POWER_MAP, 2, wantedSettings[0]));
toSend.replace("_MODE_", createOptionSelector("MODE", hp.MODE_MAP, 5, wantedSettings[1]));
toSend.replace("_TEMP_", createOptionSelector("TEMP", hp.TEMP_MAP, 16, wantedSettings[2]));
toSend.replace("_FAN_", createOptionSelector("FAN", hp.FAN_MAP, 6, wantedSettings[3]));
toSend.replace("_VANE_", createOptionSelector("VANE", hp.VANE_MAP, 7, wantedSettings[4]));
toSend.replace("_DIR_", createOptionSelector("DIR", hp.DIR_MAP, 7, wantedSettings[5]));
server.send(200, "text/html", toSend);
delay(100);
}

void change_states() {
if (server.hasArg("CONNECT")) {
hp.connect(&Serial);
}
else {
String currentSettings[6] = {};
hp.getSettings(currentSettings);
boolean update = false;
if (server.hasArg("POWER")) {
wantedSettings[0] = hp.POWER_MAP[server.arg("POWER").toInt()];
update = currentSettings[0] != wantedSettings[0] ? true : update;
}
if (server.hasArg("MODE")) {
wantedSettings[1] = hp.MODE_MAP[server.arg("MODE").toInt()];
update = currentSettings[1] != wantedSettings[1] ? true : update;
}
if (server.hasArg("TEMP")) {
wantedSettings[2] = hp.TEMP_MAP[server.arg("TEMP").toInt()];
update = currentSettings[2] != wantedSettings[2] ? true : update;
}
if (server.hasArg("FAN")) {
wantedSettings[3] = hp.FAN_MAP[server.arg("FAN").toInt()];
update = currentSettings[3] != wantedSettings[3] ? true : update;
}
if (server.hasArg("VANE")) {
wantedSettings[4] = hp.VANE_MAP[server.arg("VANE").toInt()];
update = currentSettings[4] != wantedSettings[4] ? true : update;
}
if (server.hasArg("DIR")) {
wantedSettings[5] = hp.DIR_MAP[server.arg("DIR").toInt()];
update = currentSettings[5] != wantedSettings[5] ? true : update;
}
if (update) {
hp.setSettings(wantedSettings);
hp.update();
}
}
}
17 changes: 17 additions & 0 deletions examples/heatPump_test/heatPump_test.ino
@@ -0,0 +1,17 @@

#include <HeatPump.h>

void setup() {
// put your setup code here, to run once:
HeatPump hp;
hp.connect(&Serial);
hp.update(); // power mode temp fan vane dir
String settings[6]={"ON","FAN","26","4","3","|"};
hp.setSettings(settings);
hp.update();
}

void loop() {
// put your main code here, to run repeatedly:

}
9 changes: 9 additions & 0 deletions library.properties
@@ -0,0 +1,9 @@
name=HeatPump
version=1.0.0
author=Al Betschart
maintainer=AL <al@swicago.com>
sentence=Allows Arduino boards to serial communicate with Mitsubishi heat pumps via port cn105
paragraph=Currently only support Mitsubishi Heat Pumps<br/>Library allows to pass a reference of the Serial you wish to use, such as Serial(esp8266) or Serial1(arduino micro pro).<br/>The library will "begin" the serial comms at 2400baud 8bits even parity.<br/>Make sure your board can handle 5V TTL, otherwise use a level shifter.<br/>Pull TX and RX to 5V with 10k resistors, otherwise the heat pump will not accept the connection.
category=Device Control
url=http://http://www.mitsubishicomfort.com/
architectures=*
138 changes: 138 additions & 0 deletions src/HeatPump.cpp
@@ -0,0 +1,138 @@
/*
HeatPump.cpp - Mitsubishi Heat Pump control library for Arduino
Copyright (c) 2017 Al Betschart. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "HeatPump.h"

// Initialize Class Variables //////////////////////////////////////////////////

const byte HeatPump::CONNECT[] = {0xfc, 0x5a, 0x01, 0x30, 0x02, 0xca, 0x01, 0xa8};
const byte HeatPump::HEADER[] = {0xfc, 0x41, 0x01, 0x30, 0x10, 0x01, 0x9f, 0x00};
const byte HeatPump::PAD[] = {0x00, 0x00, 0x00, 0x00, 0x00};
const byte HeatPump::POWER[] = {0x00, 0x01};
const String HeatPump::POWER_MAP[] = {"OFF", "ON"};
const byte HeatPump::MODE[] = {0x01, 0x02, 0x03, 0x07, 0x08};
const String HeatPump::MODE_MAP[] = {"HEAT", "DRY", "COOL", "FAN", "AUTO"};
const byte HeatPump::TEMP[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
const String HeatPump::TEMP_MAP[] = {"31", "30", "29", "28", "27", "26", "25", "24", "23", "22", "21", "20", "19", "18", "17", "16"};
const byte HeatPump::FAN[] = {0x00, 0x01, 0x02, 0x03, 0x05, 0x06};
const String HeatPump::FAN_MAP[] = {"AUTO", "QUIET", "1", "2", "3", "4"};
const byte HeatPump::VANE[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07};
const String HeatPump::VANE_MAP[] = {"AUTO", "1", "2", "3", "4", "5", "SWING"};
const byte HeatPump::DIR[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x08, 0x0c};
const String HeatPump::DIR_MAP[] = {"<<", "<", "|", ">", ">>", "<>", "SWING"};
const byte HeatPump::ROOM_TEMP[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f};
const String HeatPump::ROOM_TEMP_MAP[] = {"10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25",
"26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41"};

const byte HeatPump::CONTROL_PACKET_VALUES[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x80};
const String HeatPump::CONTROL_PACKET_VALUES_MAP[] = {"POWER", "MODE", "TEMP", "FAN", "VANE", "DIR"};
const int HeatPump::CONTROL_PACKET_POSITIONS[] = {3, 4, 5, 6, 7, 10};
const String HeatPump::CONTROL_PACKET_POSITIONS_MAP[] = {"POWER", "MODE", "TEMP", "FAN", "VANE", "DIR"};

String HeatPump::currentSettings[] = {POWER_MAP[0], MODE_MAP[0], TEMP_MAP[0], FAN_MAP[0], VANE_MAP[0], DIR_MAP[0]};
String HeatPump::wantedSettings[] = {POWER_MAP[0], MODE_MAP[0], TEMP_MAP[0], FAN_MAP[0], VANE_MAP[0], DIR_MAP[0]};

HardwareSerial * HeatPump::_HardSerial;

// Constructors ////////////////////////////////////////////////////////////////

HeatPump::HeatPump() {}

// Public Methods //////////////////////////////////////////////////////////////

void HeatPump::connect(HardwareSerial *serial) {
_HardSerial = serial;
_HardSerial->begin(2400, SERIAL_8E1);
delay(2000);
for (int i = 0; i < 8; i++) {
_HardSerial->write((uint8_t)CONNECT[i]);
}
delay(1100);
for (int i = 0; i < 8; i++) {
_HardSerial->write((uint8_t)CONNECT[i]);
}
delay(2000);
}

void HeatPump::update() {
byte packet[22] = {};
createPacket(packet, HeatPump::wantedSettings);
for (int i = 0; i < 22; i++) {
_HardSerial->write((uint8_t)packet[i]);
}
delay(1000);
}

void HeatPump::setSettings(String settings[]) {
for (int i = 0; i < 6; i++) {
HeatPump::wantedSettings[i] = settings[i];
}
}

void HeatPump::getSettings(String *settings) {
settings = HeatPump::currentSettings;
}

int HeatPump::findValueByByte(const byte values[], int len, byte value) {
for (int i = 0; i < len; i++) {
if (values[i] == value) {
return i;
}
}
return -1;
}
int HeatPump::findValueByString(const String values[], int len, String value) {
for (int i = 0; i < len; i++) {
if (values[i] == value) {
return i;
}
}
return -1;
}

byte HeatPump::checkSum(byte bytes[], int len) {
byte sum = 0;
for (int i = 0; i < len; i++) {
sum += bytes[i];
}
return (0xfc - sum) & 0xff;
}

void HeatPump::createPacket(byte *packet, String settings[]) {
byte data[21] = {};
for (int i = 0; i < 8; i++) {
data[i] = HEADER[i];
}
data[8] = HeatPump::POWER[findValueByString(HeatPump::POWER_MAP, 2, settings[0])];
data[9] = HeatPump::MODE[findValueByString(HeatPump::MODE_MAP, 5, settings[1])];
data[10] = HeatPump::TEMP[findValueByString(HeatPump::TEMP_MAP, 16, settings[2])];
data[11] = HeatPump::FAN[findValueByString(HeatPump::FAN_MAP, 6, settings[3])];
data[12] = HeatPump::VANE[findValueByString(HeatPump::VANE_MAP, 7, settings[4])];
data[13] = 0x00;
data[14] = 0x00;
data[15] = HeatPump::DIR[findValueByString(HeatPump::DIR_MAP, 7, settings[5])];
for (int i = 0; i < 5; i++) {
data[i + 16] = PAD[i];
}
byte chkSum = checkSum(data, 21);
for (int i = 0; i < 21; i++) {
packet[i] = data[i];
}
packet[21] = chkSum;
}
71 changes: 71 additions & 0 deletions src/HeatPump.h
@@ -0,0 +1,71 @@
/*
HeatPump.h - Mitsubishi Heat Pump control library for Arduino
Copyright (c) 2017 Al Betschart. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdint.h>
#include <WString.h>
#include <HardwareSerial.h>
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

typedef uint8_t byte;

class HeatPump
{
private:
static const byte CONNECT[];
static const byte HEADER[];
static const byte PAD[];
static const byte POWER[];
static const byte MODE[];
static const byte TEMP[];
static const byte FAN[];
static const byte VANE[];
static const byte DIR[];
static const byte ROOM_TEMP[];
static const byte CONTROL_PACKET_VALUES[];
static const String CONTROL_PACKET_VALUES_MAP[];
static const int CONTROL_PACKET_POSITIONS[];
static const String CONTROL_PACKET_POSITIONS_MAP[];

static String currentSettings[];
static String wantedSettings[];

static void createPacket(byte *packet, String settings[]);
static int findValueByByte(const byte values[], int len, byte value);
static int findValueByString(const String values[], int len, String value);
static byte checkSum(byte bytes[], int len);

static HardwareSerial * _HardSerial;

public:
static const String POWER_MAP[];
static const String MODE_MAP[];
static const String TEMP_MAP[];
static const String FAN_MAP[];
static const String VANE_MAP[];
static const String DIR_MAP[];
static const String ROOM_TEMP_MAP[];
HeatPump();
void connect(HardwareSerial *serial);
void update();
void setSettings(String settings[]);
void getSettings(String *settings);
};

0 comments on commit 954aff2

Please sign in to comment.