forked from SwiCago/HeatPump
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial commit of arduino mitsubishi package HeatPump
- Loading branch information
0 parents
commit 954aff2
Showing
5 changed files
with
362 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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("<", "<"); | ||
toEncode.replace(">", ">"); | ||
toEncode.replace("|", "|"); | ||
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(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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: | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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=* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
}; |