Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Revolt NX-4608 #217

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions WThermostat/src/WThermostat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "WThermostat_BHT_002_GBLW.h"
#include "WThermostat_BAC_002_ALW.h"
#include "WThermostat_ET81W.h"
#include "WThermostat_NX_4608.h"
#include "WThermostat_HY08WE.h"
#include "WThermostat_ME81H.h"
#include "WThermostat_MK70GBH.h"
Expand Down Expand Up @@ -65,6 +66,9 @@ void setup() {
case MODEL_DLX_LH01 :
device = new WThermostat_DLX_LH01(network, thermostatModel, wClock);
break;
case MODEL_NX_4608 :
device = new WThermostat_NX_4608(network, thermostatModel, wClock);
break;
default :
network->error(F("Can't start device. Wrong thermostatModel (%d)"), thermostatModel->getByte());
}
Expand Down
4 changes: 3 additions & 1 deletion WThermostat/src/WThermostat.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#define MODEL_ME102H 6
#define MODEL_CALYPSOW 7
#define MODEL_DLX_LH01 8
#define MODEL_NX_4608 9
#define PIN_STATE_HEATING_RELAY 5
#define NOT_SUPPORTED 0x00

Expand Down Expand Up @@ -139,6 +140,7 @@ public :
page->printf(HTTP_COMBOBOX_ITEM, "5", (this->thermostatModel->getByte() == 5 ? HTTP_SELECTED : ""), "Minco Heat MK70GB-H");
page->printf(HTTP_COMBOBOX_ITEM, "7", (this->thermostatModel->getByte() == 7 ? HTTP_SELECTED : ""), "VH Control Calypso-W");
page->printf(HTTP_COMBOBOX_ITEM, "8", (this->thermostatModel->getByte() == 8 ? HTTP_SELECTED : ""), "DLX-LH01");
page->printf(HTTP_COMBOBOX_ITEM, "9", (this->thermostatModel->getByte() == 9 ? HTTP_SELECTED : ""), "Revolt NX-4608");
page->print(FPSTR(HTTP_COMBOBOX_END));
//Checkbox
page->printf(HTTP_CHECKBOX_OPTION, "sb", "sb", (this->switchBackToAuto->getBoolean() ? HTTP_CHECKED : ""), "", "Auto mode from manual mode at next schedule period change <br> (not at model ET-81W and ME81AH)");
Expand Down Expand Up @@ -305,8 +307,8 @@ public :
bool heating = false;
if ((this->supportingHeatingRelay->getBoolean()) && (state != nullptr)) {
heating = digitalRead(PIN_STATE_HEATING_RELAY);
this->state->setString(heating ? STATE_HEATING : STATE_OFF);
}
this->state->setString(heating ? STATE_HEATING : STATE_OFF);
}
WTuyaDevice::loop(now);
updateCurrentSchedulePeriod();
Expand Down
251 changes: 251 additions & 0 deletions WThermostat/src/WThermostat_NX_4608.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
#ifndef THERMOSTAT_NX_4608_H
#define THERMOSTAT_NX_4608_H

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include "WThermostat.h"
#include "WThermostat_ME102H.h"

class WThermostat_NX_4608 : public WThermostat {
public :
WThermostat_NX_4608(WNetwork* network, WProperty* thermostatModel, WClock* wClock)
: WThermostat(network, thermostatModel, wClock) {
network->debug(F("WThermostat_NX_4608 created"));
}

virtual void configureCommandBytes() {
this->byteDeviceOn = 0x01;
this->byteTemperatureActual = 0x03;
this->byteTemperatureTarget = 0x02;
this->byteTemperatureFloor = 0x67;
this->temperatureFactor = 10.0f;
this->byteSchedulesMode = 0x04;
this->byteLocked = 0x06;
this->byteSchedules = NOT_SUPPORTED;
this->byteSchedulingPosHour = 1;
this->byteSchedulingPosMinute = 0;
this->byteSchedulingDays = 18;
//custom
this->byteState = 0x66;
this->byteSensorSelection = 0x74;
}

virtual void initializeProperties() {
WThermostat::initializeProperties();
//2021-01-14 - schedulesMode
this->schedulesMode->clearEnums();
this->schedulesMode->addEnumString(SCHEDULES_MODE_OFF);
this->schedulesMode->addEnumString(SCHEDULES_MODE_AUTO);
this->schedulesMode->addEnumString(SCHEDULES_MODE_HOLIDAY);
this->schedulesMode->addEnumString(SCHEDULES_MODE_HOLD);
//sensorSelection
this->sensorSelection = new WProperty("sensorSelection", "Sensor Selection", STRING, TYPE_THERMOSTAT_MODE_PROPERTY);
this->sensorSelection->addEnumString(SENSOR_SELECTION_INTERNAL);
this->sensorSelection->addEnumString(SENSOR_SELECTION_FLOOR);
this->sensorSelection->addEnumString(SENSOR_SELECTION_BOTH);
this->sensorSelection->setVisibility(MQTT);
this->sensorSelection->setOnChange(std::bind(&WThermostat_NX_4608::sensorSelectionToMcu, this, std::placeholders::_1));
this->addProperty(this->sensorSelection);
//Heating Relay and State property
this->state = new WProperty("state", "State", STRING, TYPE_HEATING_COOLING_PROPERTY);
this->state->setReadOnly(true);
this->state->addEnumString(STATE_OFF);
this->state->addEnumString(STATE_HEATING);
this->addProperty(state);
}

protected :

virtual bool processStatusCommand(byte cByte, byte commandLength) {
//Status report from MCU
bool changed = false;
bool knownCommand = WThermostat::processStatusCommand(cByte, commandLength);

if (!knownCommand) {
const char* newS;
if (cByte == this->byteSensorSelection) {
if (commandLength == 0x05) {
//sensor selection -
//internal: 55 aa 03 07 00 05 74 04 00 01 00
//floor: 55 aa 03 07 00 05 74 04 00 01 01
//both: 55 aa 03 07 00 05 74 04 00 01 02
newS = this->sensorSelection->getEnumString(receivedCommand[10]);
if (newS != nullptr) {
changed = ((changed) || (this->sensorSelection->setString(newS)));
knownCommand = true;
}
}
}
else if (cByte == this->byteState) {
if (commandLength == 0x05){
//heating state
// on: 55 aa 03 07 00 05 01 01 00 01 01
// off: 55 aa 03 07 00 05 01 01 00 01 00
newS = this->state->getEnumString(receivedCommand[10]);
if (newS != nullptr) {
changed = ((changed) || (this->state->setString(newS)));
}
knownCommand = true;
}
} else{
//consume some unsupported commands
switch (cByte) {
case 0x0c :
// unknown bitmap
// MCU: 55 aa 03 07 00 05 0c 05 00 01 00
// MCU: 55 aa 03 07 00 05 0c 05 00 01 08
knownCommand = true;
break;
case 0x65 :
// unknown boolean
// MCU: 55 aa 03 07 00 05 65 01 00 01 00
knownCommand = true;
break;
case 0x68 :
// number of holiday days
// MCU: 5d / 55 aa 03 07 00 08 68 02 00 04 00 00 00 05
// MCU: 10d / 55 aa 03 07 00 08 68 02 00 04 00 00 00 0a
knownCommand = true;
break;
case 0x69 :
// unknown integer
// MCU: 55 aa 03 07 00 08 69 02 00 04 00 00 00 0f
knownCommand = true;
break;
case 0x6a :
// disable high temp protection for external sensor (AA Code 2)
// MCU: off / 55 aa 03 07 00 05 6a 01 00 01 00
// MCU: on / 55 aa 03 07 00 05 6a 01 00 01 01
knownCommand = true;
break;
case 0x6b :
// disable low temp protection for external sensor (A9 Code 2)
// MCU: off / 55 aa 03 07 00 05 6b 01 00 01 00
// MCU: on / 55 aa 03 07 00 05 6b 01 00 01 01
knownCommand = true;
break;
case 0x6c :
// unknown boolean
// MCU: 55 aa 03 07 00 05 6c 01 00 01 00
knownCommand = true;
break;
case 0x6d :
// Temperature correction in millidegree (A1)
// MCU: 0C / 55 aa 03 07 00 08 6d 02 00 04 00 00 00 00
// MCU: -2C / 55 aa 03 07 00 08 6d 02 00 04 ff ff ff ec
knownCommand = true;
break;
case 0x6e :
// hysteresis in millidegree (A2)
// MCU: 0.5C / 55 aa 03 07 00 08 6e 02 00 04 00 00 00 05
// MCU: 1C / 55 aa 03 07 00 08 6e 02 00 04 00 00 00 0a
// MCU: 1.5C / 55 aa 03 07 00 08 6e 02 00 04 00 00 00 0f
// MCU: 2C / 55 aa 03 07 00 08 6e 02 00 04 00 00 00 14
// MCU: 2.5C / 55 aa 03 07 00 08 6e 02 00 04 00 00 00 19
knownCommand = true;
break;
case 0x6f :
// hysteresis in degree for external sensor (AB)
// MCU: 1C / 55 aa 03 07 00 08 6f 02 00 04 00 00 00 01
// MCU: 2C / 55 aa 03 07 00 08 6f 02 00 04 00 00 00 02
// ...
// MCU: 9C / 55 aa 03 07 00 08 6f 02 00 04 00 00 00 09
knownCommand = true;
break;
case 0x70 :
// max temp external sensor (AA Code 1)
// MCU: 35C / 55 aa 03 07 00 08 70 02 00 04 00 00 00 23
// ...
// MCU: 70C / 55 aa 03 07 00 08 70 02 00 04 00 00 00 46
case 0x71 :
// min temp external sensor (A9 Code 1)
// MCU: 1C / 55 aa 03 07 00 08 71 02 00 04 00 00 00 01
// MCU: 5C / 55 aa 03 07 00 08 71 02 00 04 00 00 00 05
// MCU: 10C / 55 aa 03 07 00 08 71 02 00 04 00 00 00 0a
knownCommand = true;
break;
case 0x72 :
// max temp (A8)
// MCU: 20C / 55 aa 03 07 00 08 72 02 00 04 00 00 00 14
// MCU: 21C / 55 aa 03 07 00 08 72 02 00 04 00 00 00 15
// ...
// MCU: 35C / 55 aa 03 07 00 08 72 02 00 04 00 00 00 23
// ...
// MCU: 70C / 55 aa 03 07 00 08 72 02 00 04 00 00 00 46
knownCommand = true;
break;
case 0x73 :
// min temp (A7)
// MCU: 1C / 55 aa 03 07 00 08 73 02 00 04 00 00 00 01
// MCU: 2C / 55 aa 03 07 00 08 73 02 00 04 00 00 00 02
// MCU: 3C / 55 aa 03 07 00 08 73 02 00 04 00 00 00 03
// ...
// MCU: 9C / 55 aa 03 07 00 08 73 02 00 04 00 00 00 09
// MCU: 10C / 55 aa 03 07 00 08 73 02 00 04 00 00 00 0a
knownCommand = true;
break;
case 0x75 :
// poweron state (A4)
// saved: 55 aa 03 07 00 05 75 04 00 01 00
// off: 55 aa 03 07 00 05 75 04 00 01 01
// on: 55 aa 03 07 00 05 75 04 00 01 02
knownCommand = true;
break;
case 0x76 :
// weekend mode (A6)
// MCU: 5+2 / 55 aa 03 07 00 05 76 04 00 01 00
// MCU: 6+1 / 55 aa 03 07 00 05 76 04 00 01 01
// MCU: 7 / 55 aa 03 07 00 05 76 04 00 01 02
knownCommand = true;
break;
case 0x77 :
// unknown raw
// MCU: 55 aa 03 07 00 0d 77 00 00 09 06 00 14 08 00 0f 0b 1e 0f
knownCommand = true;
break;
case 0x78 :
// unknown raw
// MCU: 55 aa 03 07 00 0d 78 00 00 09 0d 1e 0f 11 00 0f 96 00 0f
knownCommand = true;
break;
case 0x79 :
// unknown raw
// MCU: 55 aa 03 07 00 0d 79 00 00 09 06 00 14 08 00 0f 0b 1e 0f
knownCommand = true;
break;
case 0x7A :
// unknown raw
// MCU: 55 aa 03 07 00 0d 7a 00 00 09 0d 1e 0f 11 00 0f 16 00 0f
knownCommand = true;
break;
}
}
}
if (changed) {
notifyState();
}
return knownCommand;
}

void sensorSelectionToMcu(WProperty* property) {
if (!isReceivingDataFromMcu()) {
byte sm = property->getEnumIndex();
if (sm != 0xFF) {
//send to device
//internal: 55 aa 03 06 00 05 74 05 00 01 00
//floor: 55 aa 03 06 00 05 74 05 00 01 01
//both: 55 aa 03 06 00 05 74 05 00 01 02
unsigned char cm[] = { 0x55, 0xAA, 0x03, 0x06, 0x00, 0x05,
this->byteSensorSelection, 0x05, 0x00, 0x01, sm};
commandCharsToSerial(11, cm);
}
}
}

private :
WProperty* sensorSelection;
byte byteSensorSelection;
byte byteState;
};

#endif
Binary file added docs/NX-4608/NX4608_11_173788.pdf
Binary file not shown.
Binary file added docs/NX-4608/NX4608_11_174965.pdf
Binary file not shown.
Binary file added docs/NX-4608/PCB Layout.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.