Skip to content

Instantly share code, notes, and snippets.

@basst85
Created October 17, 2016 07:56
Show Gist options
  • Save basst85/4bdcc32981f25a48892d1ef92f621263 to your computer and use it in GitHub Desktop.
Save basst85/4bdcc32981f25a48892d1ef92f621263 to your computer and use it in GitHub Desktop.
ToonThermostat.cpp with changed user-agent and poll interval
#include "stdafx.h"
#include "ToonThermostat.h"
#include "../main/Helper.h"
#include "../main/Logger.h"
#include "hardwaretypes.h"
#include "../main/localtime_r.h"
#include "../json/json.h"
#include "../main/RFXtrx.h"
#include "../main/SQLHelper.h"
#include "../httpclient/HTTPClient.h"
#include "../main/mainworker.h"
#include "../json/json.h"
#define round(a) ( int ) ( a + .5 )
#ifdef _DEBUG
// #define DEBUG_ToonThermostat
#endif
#ifdef DEBUG_ToonThermostat2
void SaveString2Disk(std::string str, std::string filename)
{
FILE *fOut = fopen(filename.c_str(), "wb+");
if (fOut)
{
fwrite(str.c_str(), 1, str.size(), fOut);
fclose(fOut);
}
}
#endif
#ifdef DEBUG_ToonThermostat
std::string ReadFile(std::string filename)
{
std::ifstream file;
std::string sResult = "";
file.open(filename.c_str());
if (!file.is_open())
return "";
std::string sLine;
while (!file.eof())
{
getline(file, sLine);
sResult += sLine;
}
file.close();
return sResult;
}
#endif
const std::string TOON_HOST = "https://toonopafstand.eneco.nl";
//const std::string TOON_HOST = "https://toonopafstand-acc.quby.nl"; //needs URL encoding
const std::string TOON_LOGIN_PATH = "/toonMobileBackendWeb/client/login";
const std::string TOON_LOGOUT_PATH = "/toonMobileBackendWeb/client/auth/logout";
const std::string TOON_LOGINCHECK_PATH = "/toonMobileBackendWeb/client/checkIfLoggedIn";
const std::string TOON_AGREEMENT_PATH = "/toonMobileBackendWeb/client/auth/start";
const std::string TOON_UPDATE_PATH = "/toonMobileBackendWeb/client/auth/retrieveToonState";
const std::string TOON_CHANGE_SCHEME = "/toonMobileBackendWeb/client/auth/schemeState";
const std::string TOON_TEMPSET_PATH = "/toonMobileBackendWeb/client/auth/setPoint";
const std::string TOON_CHANGE_SCREEN_PATH = "/toonMobileBackendWeb/client/auth/kpi/changedScreen";
const std::string TOON_TAB_PRESSED_PATH = "/toonMobileBackendWeb/client/auth/kpi/tabPressed";
const std::string TOON_GET_ELECTRIC_GRAPH = "/toonMobileBackendWeb/client/auth/getElecGraphData";
const std::string TOON_GET_GAS_GRAPH = "/toonMobileBackendWeb/client/auth/getGasGraphData"; //?smartMeter=false
const std::string TOON_SWITCH_POWER = "/toonMobileBackendWeb/client/auth/smartplug/setTarget";
const std::string TOON_SWITCH_ALL = "/toonMobileBackendWeb/client/auth/smartplug/switchAll";
const std::string TOON_USERAGENT = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36";
//enum _eProgramStates {
// PROG_MANUAL = 0,
// PROG_BASE, //1
// PROG_TEMPOVERRIDE, //2
// PROG_PROGOVERRIDE, //3
// PROG_HOLIDAY, //4
// PROG_MANUALHOLIDAY, //5
// PROG_AWAYNOW, //6
// PROG_DAYOFF, //7
// PROG_LOCKEDBASE //8
//};
//enum _eActiveStates {
// STATE_RELAX = 0,
// STATE_ACTIVE, //1
// STATE_SLEEP, //2
// STATE_AWAY, //3
// STATE_HOLIDAY //4
//};
CToonThermostat::CToonThermostat(const int ID, const std::string &Username, const std::string &Password, const int &Agreement) :
m_UserName(Username),
m_Password(Password),
m_Agreement(Agreement)
{
m_HwdID=ID;
memset(&m_p1power, 0, sizeof(m_p1power));
memset(&m_p1gas, 0, sizeof(m_p1gas));
m_p1power.len = sizeof(P1Power)-1;
m_p1power.type = pTypeP1Power;
m_p1power.subtype = sTypeP1Power;
m_p1power.ID = 1;
m_p1gas.len = sizeof(P1Gas)-1;
m_p1gas.type = pTypeP1Gas;
m_p1gas.subtype = sTypeP1Gas;
m_p1gas.ID = 1;
m_ClientID = "";
m_ClientIDChecksum = "";
m_stoprequested = false;
m_lastSharedSendElectra = 0;
m_lastSharedSendGas = 0;
m_lastgasusage = 0;
m_lastelectrausage = 0;
m_lastelectradeliv = 0;
m_LastUsage1 = 0;
m_LastUsage2 = 0;
m_OffsetUsage1 = 0;
m_OffsetUsage2 = 0;
m_LastDeliv1 = 0;
m_LastDeliv2 = 0;
m_OffsetDeliv1 = 0;
m_OffsetDeliv2 = 0;
m_bDoLogin = true;
HTTPClient::SetUserAgent(TOON_USERAGENT);
}
CToonThermostat::~CToonThermostat(void)
{
}
void CToonThermostat::Init()
{
m_ClientID = "";
m_ClientIDChecksum = "";
m_stoprequested = false;
m_lastSharedSendElectra = 0;
m_lastSharedSendGas = 0;
m_lastgasusage = 0;
m_lastelectrausage = 0;
m_lastelectradeliv = 0;
m_LastUsage1=0;
m_LastUsage2=0;
m_OffsetUsage1=0;
m_OffsetUsage2=0;
m_LastDeliv1 = 0;
m_LastDeliv2 = 0;
m_OffsetDeliv1 = 0;
m_OffsetDeliv2 = 0;
//Get Last meter counter values for Usage/Delivered
std::vector<std::vector<std::string> > result;
result = m_sql.safe_query("SELECT ID FROM DeviceStatus WHERE (HardwareID==%d) AND (DeviceID==1) AND ([Type]==%d) AND (SubType==%d)", m_HwdID, pTypeP1Power, sTypeP1Power);
if (!result.empty())
{
unsigned long devID = (unsigned long)atol(result[0][0].c_str());
result = m_sql.safe_query("SELECT MAX(Counter1), MAX(Counter2), MAX(Counter3), MAX(Counter4) FROM Multimeter_Calendar WHERE (DeviceRowID==%ld)", devID);
if (result.size() > 0)
{
std::vector<std::string> sd = *result.begin();
m_OffsetUsage1 = (unsigned long)atol(sd[0].c_str());
m_OffsetDeliv1 = (unsigned long)atol(sd[1].c_str());
m_OffsetUsage2 = (unsigned long)atol(sd[2].c_str());
m_OffsetDeliv2 = (unsigned long)atol(sd[3].c_str());
}
}
m_bDoLogin = true;
}
bool CToonThermostat::StartHardware()
{
Init();
//Start worker thread
m_thread = boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(&CToonThermostat::Do_Work, this)));
m_bIsStarted=true;
sOnConnected(this);
return (m_thread!=NULL);
}
bool CToonThermostat::StopHardware()
{
if (m_thread!=NULL)
{
assert(m_thread);
m_stoprequested = true;
m_thread->join();
}
m_bIsStarted=false;
if (!m_bDoLogin)
Logout();
return true;
}
#define TOON_POLL_INTERVAL 60
void CToonThermostat::Do_Work()
{
int sec_counter = TOON_POLL_INTERVAL-5;
_log.Log(LOG_STATUS,"ToonThermostat: Worker started...");
while (!m_stoprequested)
{
sleep_seconds(1);
sec_counter++;
if (sec_counter % 12 == 0) {
mytime(&m_LastHeartbeat);
}
if (sec_counter % TOON_POLL_INTERVAL == 0)
{
GetMeterDetails();
}
}
_log.Log(LOG_STATUS,"ToonThermostat: Worker stopped...");
}
void CToonThermostat::SendSetPointSensor(const unsigned char Idx, const float Temp, const std::string &defaultname)
{
_tThermostat thermos;
thermos.subtype=sTypeThermSetpoint;
thermos.id1=0;
thermos.id2=0;
thermos.id3=0;
thermos.id4=Idx;
thermos.dunit=0;
thermos.temp=Temp;
sDecodeRXMessage(this, (const unsigned char *)&thermos, defaultname.c_str(), 255);
}
void CToonThermostat::UpdateSwitch(const unsigned char Idx, const bool bOn, const std::string &defaultname)
{
bool bDeviceExits = true;
char szIdx[10];
sprintf(szIdx, "%X%02X%02X%02X", 0, 0, 0, Idx);
std::vector<std::vector<std::string> > result;
result = m_sql.safe_query("SELECT Name,nValue,sValue FROM DeviceStatus WHERE (HardwareID==%d) AND (Type==%d) AND (SubType==%d) AND (DeviceID=='%q')",
m_HwdID, pTypeLighting2, sTypeAC, szIdx);
if (!result.empty())
{
//check if we have a change, if not do not update it
int nvalue = atoi(result[0][1].c_str());
if ((!bOn) && (nvalue == 0))
return;
if ((bOn && (nvalue != 0)))
return;
}
//Send as Lighting 2
tRBUF lcmd;
memset(&lcmd, 0, sizeof(RBUF));
lcmd.LIGHTING2.packetlength = sizeof(lcmd.LIGHTING2) - 1;
lcmd.LIGHTING2.packettype = pTypeLighting2;
lcmd.LIGHTING2.subtype = sTypeAC;
lcmd.LIGHTING2.id1 = 0;
lcmd.LIGHTING2.id2 = 0;
lcmd.LIGHTING2.id3 = 0;
lcmd.LIGHTING2.id4 = Idx;
lcmd.LIGHTING2.unitcode = 1;
int level = 15;
if (!bOn)
{
level = 0;
lcmd.LIGHTING2.cmnd = light2_sOff;
}
else
{
level = 15;
lcmd.LIGHTING2.cmnd = light2_sOn;
}
lcmd.LIGHTING2.level = level;
lcmd.LIGHTING2.filler = 0;
lcmd.LIGHTING2.rssi = 12;
sDecodeRXMessage(this, (const unsigned char *)&lcmd.LIGHTING2, defaultname.c_str(), 255);
}
std::string CToonThermostat::GetRandom()
{
//5BA37E41-B5C8-4C19-AA81-9EA82430D7EA
char szTmp[100];
sprintf(szTmp,"%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
// 32 bits for "time_low"
rand() % 0xFFFF, rand() % 0xFFFF,
// 16 bits for "time_mid"
rand() % 0xFFFF,
// 16 bits for "time_hi_and_version",
// four most significant bits holds version number 4
rand() % 0xFFFF | 0x4000,
// 16 bits, 8 bits for "clk_seq_hi_res",
// 8 bits for "clk_seq_low",
// two most significant bits holds zero and one for variant DCE1.1
rand() % 0xFFFF | 0x8000,
// 48 bits for "node"
rand() % 0xFFFF, rand() % 0xFFFF, rand() % 0xFFFF
);
std::string ret=szTmp;
return ret;
}
bool CToonThermostat::Login()
{
if (m_ClientID != "")
{
Logout();
}
m_ClientID = "";
std::stringstream sstr;
sstr << "username=" << m_UserName << "&password=" << m_Password;
std::string szPostdata=sstr.str();
std::vector<std::string> ExtraHeaders;
std::string sResult;
std::string sURL = TOON_HOST + TOON_LOGIN_PATH;
if (!HTTPClient::POST(sURL, szPostdata, ExtraHeaders, sResult))
{
_log.Log(LOG_ERROR,"ToonThermostat: Error login!");
return false;
}
Json::Value root;
Json::Reader jReader;
if (!jReader.parse(sResult, root))
{
_log.Log(LOG_ERROR, "ToonThermostat: Invalid data received, or invalid username/password!");
return false;
}
if (root["clientId"].empty() == true)
{
_log.Log(LOG_ERROR, "ToonThermostat: Invalid data received, or invalid username/password!");
return false;
}
m_ClientID = root["clientId"].asString();
if (root["clientIdChecksum"].empty() == true)
{
_log.Log(LOG_ERROR, "ToonThermostat: Invalid data received, or invalid username/password!");
return false;
}
m_ClientIDChecksum = root["clientIdChecksum"].asString();
std::string agreementId;
std::string agreementIdChecksum;
if (root["agreements"].empty() == true)
{
_log.Log(LOG_ERROR, "ToonThermostat: Invalid data received, or invalid username/password!");
return false;
}
if (root["agreements"].size() < (size_t)(m_Agreement+1))
{
_log.Log(LOG_ERROR, "ToonThermostat: Agreement not found, did you setup your toon correctly?");
return false;
}
agreementId = root["agreements"][m_Agreement]["agreementId"].asString();
agreementIdChecksum = root["agreements"][m_Agreement]["agreementIdChecksum"].asString();
std::stringstream sstr2;
sstr2 << "clientId=" << m_ClientID
<< "&clientIdChecksum=" << m_ClientIDChecksum
<< "&agreementId=" << agreementId
<< "&agreementIdChecksum=" << agreementIdChecksum
<< "&random=" << GetRandom();
szPostdata = sstr2.str();
sResult = "";
sURL = TOON_HOST + TOON_AGREEMENT_PATH;
if (!HTTPClient::POST(sURL, szPostdata, ExtraHeaders, sResult))
{
_log.Log(LOG_ERROR, "ToonThermostat: Error login!");
return false;
}
root.clear();
if (!jReader.parse(sResult, root))
{
_log.Log(LOG_ERROR, "ToonThermostat: Invalid data received!");
return false;
}
if (root["success"].empty() == true)
{
_log.Log(LOG_ERROR, "ToonThermostat: Invalid data received!");
return false;
}
if (root["success"] == true)
{
m_bDoLogin = false;
return true;
}
return false;
}
void CToonThermostat::Logout()
{
if (m_bDoLogin)
return; //we are not logged in
std::string sResult;
std::vector<std::string> ExtraHeaders;
std::stringstream sstr2;
sstr2 << "clientId=" << m_ClientID
<< "&clientIdChecksum=" << m_ClientIDChecksum
<< "&random=" << GetRandom();
std::string szPostdata = sstr2.str();
std::string sURL = TOON_HOST + TOON_LOGOUT_PATH;
if (!HTTPClient::POST(sURL, szPostdata, ExtraHeaders, sResult))
{
_log.Log(LOG_ERROR, "ToonThermostat: Error Logout!");
}
m_ClientID = "";
m_ClientIDChecksum = "";
m_bDoLogin = true;
}
bool CToonThermostat::AddUUID(const std::string &UUID, int &idx)
{
m_sql.safe_query("INSERT INTO ToonDevices (HardwareID, UUID) VALUES (%d, '%q')",
m_HwdID, UUID.c_str());
return GetUUIDIdx(UUID, idx);
}
bool CToonThermostat::GetUUIDIdx(const std::string &UUID, int &idx)
{
std::vector<std::vector<std::string> > result;
result = m_sql.safe_query("SELECT [ROWID] FROM ToonDevices WHERE (HardwareID=%d) AND (UUID='%q')",
m_HwdID, UUID.c_str());
if (result.size() < 1)
return false;
std::vector<std::string> sd = result[0];
idx = atoi(sd[0].c_str());
return true;
}
bool CToonThermostat::GetUUIDFromIdx(const int idx, std::string &UUID)
{
std::vector<std::vector<std::string> > result;
result = m_sql.safe_query("SELECT [UUID] FROM ToonDevices WHERE (HardwareID=%d) AND (ROWID=%d)",
m_HwdID, idx);
if (result.size() < 1)
return false;
std::vector<std::string> sd = result[0];
UUID = sd[0];
return true;
}
bool CToonThermostat::SwitchLight(const std::string &UUID, const int SwitchState)
{
std::vector<std::string> ExtraHeaders;
std::string sResult;
std::stringstream sstr;
sstr << "?clientId=" << m_ClientID
<< "&clientIdChecksum=" << m_ClientIDChecksum
<< "&devUuid=" << UUID
<< "&state=" << SwitchState
<< "&random=" << GetRandom();
std::string szPostdata = sstr.str();
std::string sURL = TOON_HOST + TOON_SWITCH_POWER + szPostdata;
if (!HTTPClient::GET(sURL, ExtraHeaders, sResult))
{
_log.Log(LOG_ERROR, "ToonThermostat: Error setting switch state!");
m_bDoLogin = true;
return false;
}
Json::Value root;
Json::Reader jReader;
if (!jReader.parse(sResult, root))
{
_log.Log(LOG_ERROR, "ToonThermostat: Invalid data received!");
return false;
}
if (root["success"].empty() == true)
{
_log.Log(LOG_ERROR, "ToonThermostat: Invalid data received!");
return false;
}
return (root["success"] == true);
}
bool CToonThermostat::SwitchAll(const int SwitchState)
{
std::vector<std::string> ExtraHeaders;
std::string sResult;
std::stringstream sstr;
sstr << "?clientId=" << m_ClientID
<< "&clientIdChecksum=" << m_ClientIDChecksum
<< "&state=" << SwitchState
<< "&random=" << GetRandom();
std::string szPostdata = sstr.str();
std::string sURL = TOON_HOST + TOON_SWITCH_ALL + szPostdata;
if (!HTTPClient::GET(sURL, ExtraHeaders, sResult))
{
_log.Log(LOG_ERROR, "ToonThermostat: Error setting switch state!");
m_bDoLogin = true;
return false;
}
Json::Value root;
Json::Reader jReader;
if (!jReader.parse(sResult, root))
{
_log.Log(LOG_ERROR, "ToonThermostat: Invalid data received!");
return false;
}
if (root["success"].empty() == true)
{
_log.Log(LOG_ERROR, "ToonThermostat: Invalid data received!");
return false;
}
return (root["success"] == true);
}
bool CToonThermostat::WriteToHardware(const char *pdata, const unsigned char length)
{
if (m_UserName.size() == 0)
return false;
if (m_Password.size() == 0)
return false;
const tRBUF *pCmd = reinterpret_cast<const tRBUF *>(pdata);
if (pCmd->LIGHTING2.packettype != pTypeLighting2)
return false; //later add RGB support, if someone can provide access
int node_id = pCmd->LIGHTING2.id4;
if ((node_id == 113) || (node_id == 114) || (node_id == 115))
return false; //we can not turn on/off the internal status
int state = 0;
if (pCmd->LIGHTING2.cmnd == light2_sOn)
state = 1;
if (node_id == 254)
return SwitchAll(state);
std::string uuid;
if (!GetUUIDFromIdx(node_id, uuid))
return false;
return SwitchLight(uuid, state);
}
double CToonThermostat::GetElectricOffset(const int idx, const double currentKwh)
{
std::map<int, double>::const_iterator itt = m_OffsetElectricUsage.find(idx);
if (itt == m_OffsetElectricUsage.end())
{
//First time, lets add it
bool bExists = false;
m_OffsetElectricUsage[idx] = GetKwhMeter(idx, 1, bExists);
m_LastElectricCounter[idx] = currentKwh;
}
return m_OffsetElectricUsage[idx];
}
void CToonThermostat::GetMeterDetails()
{
if (m_UserName.size()==0)
return;
if (m_Password.size()==0)
return;
std::string sResult;
if (m_bDoLogin)
{
if (!Login())
return;
}
std::vector<std::string> ExtraHeaders;
std::stringstream sstr2;
sstr2 << "?clientId=" << m_ClientID
<< "&clientIdChecksum=" << m_ClientIDChecksum
<< "&random=" << GetRandom();
std::string szPostdata = sstr2.str();
//Get Data
#ifdef DEBUG_ToonThermostat
sResult = ReadFile("E:\\toonresult_001.txt");
#else
std::string sURL = TOON_HOST + TOON_UPDATE_PATH + szPostdata;
if (!HTTPClient::GET(sURL, ExtraHeaders, sResult))
{
_log.Log(LOG_ERROR, "ToonThermostat: Error getting current state!");
m_bDoLogin = true;
return;
}
#endif
time_t atime = mytime(NULL);
#ifdef DEBUG_ToonThermostat2
char szFileName[MAX_PATH];
static int sNum = 1;
sprintf_s(szFileName, "E:\\toonresult_%03d.txt", sNum++);
SaveString2Disk(sResult, szFileName);
#endif
Json::Value root;
Json::Reader jReader;
if (!jReader.parse(sResult, root))
{
_log.Log(LOG_ERROR, "ToonThermostat: Invalid data received!");
m_bDoLogin = true;
return;
}
if (root["success"].empty() == true)
{
_log.Log(LOG_ERROR, "ToonThermostat: ToonState request not successful, restarting..!");
m_bDoLogin = true;
return;
}
if (root["success"] == false)
{
_log.Log(LOG_ERROR, "ToonThermostat: ToonState request not successful, restarting..!");
m_bDoLogin = true;
return;
}
//ZWave Devices
if (root["deviceStatusInfo"].empty() == false)
{
if (root["deviceStatusInfo"]["device"].empty() == false)
{
int totDevices = root["deviceStatusInfo"]["device"].size();
for (int ii = 0; ii < totDevices; ii++)
{
std::string deviceName = root["deviceStatusInfo"]["device"][ii]["name"].asString();
std::string uuid = root["deviceStatusInfo"]["device"][ii]["devUUID"].asString();
int state = root["deviceStatusInfo"]["device"][ii]["currentState"].asInt();
int Idx;
if (!GetUUIDIdx(uuid, Idx))
{
if (!AddUUID(uuid, Idx))
{
_log.Log(LOG_ERROR, "ToonThermostat: Error adding UUID to database?! Uuid=%s", uuid.c_str());
return;
}
}
UpdateSwitch(Idx, state != 0, deviceName);
if (root["deviceStatusInfo"]["device"][ii]["currentUsage"].empty() == false)
{
double currentUsage = root["deviceStatusInfo"]["device"][ii]["currentUsage"].asDouble();
double DayCounter = root["deviceStatusInfo"]["device"][ii]["dayUsage"].asDouble();
//double ElecOffset = GetElectricOffset(Idx, DayCounter);
double OldDayCounter = m_LastElectricCounter[Idx];
if (DayCounter < OldDayCounter)
{
//daily counter went to zero
m_OffsetElectricUsage[Idx] += OldDayCounter;
}
m_LastElectricCounter[Idx] = DayCounter;
SendKwhMeterOldWay(Idx, 1, 255, currentUsage/1000.0, (m_OffsetElectricUsage[Idx] + m_LastElectricCounter[Idx])/1000.0, deviceName);
}
}
}
}
//thermostatInfo
if (root["thermostatInfo"].empty() == false)
{
float currentTemp = root["thermostatInfo"]["currentTemp"].asFloat() / 100.0f;
float currentSetpoint = root["thermostatInfo"]["currentSetpoint"].asFloat() / 100.0f;
SendSetPointSensor(1, currentSetpoint, "Room Setpoint");
SendTempSensor(1, 255, currentTemp, "Room Temperature");
//int programState = root["thermostatInfo"]["programState"].asInt();
//int activeState = root["thermostatInfo"]["activeState"].asInt();
if (root["thermostatInfo"]["burnerInfo"].empty() == false)
{
//burnerinfo
//0=off
//1=heating
//2=hot water
//3=pre-heating
int burnerInfo = 0;
if (root["thermostatInfo"]["burnerInfo"].isString())
{
burnerInfo = atoi(root["thermostatInfo"]["burnerInfo"].asString().c_str());
}
else if (root["thermostatInfo"]["burnerInfo"].isInt())
{
burnerInfo = root["thermostatInfo"]["burnerInfo"].asInt();
}
if (burnerInfo == 1)
{
UpdateSwitch(113, true, "HeatingOn");
UpdateSwitch(114, false, "TapwaterOn");
UpdateSwitch(115, false, "PreheatOn");
}
else if (burnerInfo == 2)
{
UpdateSwitch(113, false, "HeatingOn");
UpdateSwitch(114, true, "TapwaterOn");
UpdateSwitch(115, false, "PreheatOn");
}
else if (burnerInfo == 3)
{
UpdateSwitch(113, false, "HeatingOn");
UpdateSwitch(114, false, "TapwaterOn");
UpdateSwitch(115, true, "PreheatOn");
}
else
{
UpdateSwitch(113, false, "HeatingOn");
UpdateSwitch(114, false, "TapwaterOn");
UpdateSwitch(115, false, "PreheatOn");
}
}
}
if (root["gasUsage"].empty() == false)
{
m_p1gas.gasusage = (unsigned long)(root["gasUsage"]["meterReading"].asFloat());
}
if (root["powerUsage"].empty() == false)
{
m_p1power.powerusage1 = (unsigned long)(root["powerUsage"]["meterReadingLow"].asFloat());
m_p1power.powerusage2 = (unsigned long)(root["powerUsage"]["meterReading"].asFloat());
if ((m_p1power.powerusage1 == 0) && (m_p1power.powerusage2 == 0))
{
//New firmware does not provide meter readings anymore
unsigned long usage1 = (unsigned long)(root["powerUsage"]["dayUsage"].asFloat());
unsigned long usage2 = (unsigned long)(root["powerUsage"]["dayLowUsage"].asFloat());
if (usage1 < m_LastUsage1)
{
m_OffsetUsage1 += m_LastUsage1;
}
if (usage2 < m_LastUsage2)
{
m_OffsetUsage2 += m_LastUsage2;
}
m_p1power.powerusage1 = m_OffsetUsage1 + usage1;
m_p1power.powerusage2 = m_OffsetUsage2 + usage2;
m_LastUsage1 = usage1;
m_LastUsage2 = usage2;
}
if (root["powerUsage"]["meterReadingProdu"].empty() == false)
{
m_p1power.powerdeliv1 = (unsigned long)(root["powerUsage"]["meterReadingLowProdu"].asFloat());
m_p1power.powerdeliv2 = (unsigned long)(root["powerUsage"]["meterReadingProdu"].asFloat());
if ((m_p1power.powerdeliv1 == 0) && (m_p1power.powerdeliv2 == 0))
{
//Have not received an example from a user that has produced with the new firmware
//for now ignoring
}
}
m_p1power.usagecurrent = (unsigned long)(root["powerUsage"]["value"].asFloat()); //Watt
m_p1power.delivcurrent = (unsigned long)(root["powerUsage"]["valueProduced"].asFloat()); //Watt
if (root["powerUsage"]["valueSolar"].empty() == false)
{
float valueSolar = (float)(root["powerUsage"]["valueSolar"].asFloat());
if (valueSolar != 0)
{
SendWattMeter(1, 1, 255, valueSolar, "Solar");
}
}
}
//Send Electra if value changed, or at least every 5 minutes
if (
(m_p1power.usagecurrent != m_lastelectrausage) ||
(m_p1power.delivcurrent != m_lastelectradeliv) ||
(atime - m_lastSharedSendElectra >= 300)
)
{
if ((m_p1power.powerusage1 != 0) || (m_p1power.powerusage2 != 0) || (m_p1power.powerdeliv1 != 0) || (m_p1power.powerdeliv2 != 0))
{
m_lastSharedSendElectra = atime;
m_lastelectrausage = m_p1power.usagecurrent;
m_lastelectradeliv = m_p1power.delivcurrent;
sDecodeRXMessage(this, (const unsigned char *)&m_p1power, NULL, 255);
}
}
//Send GAS if the value changed, or at least every 5 minutes
if (
(m_p1gas.gasusage != m_lastgasusage) ||
(atime - m_lastSharedSendGas >= 300)
)
{
if (m_p1gas.gasusage != 0)
{
m_lastSharedSendGas = atime;
m_lastgasusage = m_p1gas.gasusage;
sDecodeRXMessage(this, (const unsigned char *)&m_p1gas, NULL, 255);
}
}
}
void CToonThermostat::SetSetpoint(const int idx, const float temp)
{
if (m_UserName.size() == 0)
return;
if (m_Password.size() == 0)
return;
if (m_bDoLogin == true)
{
if (!Login())
return;
}
std::string sResult;
std::vector<std::string> ExtraHeaders;
if (idx==1)
{
//Room Set Point
char szTemp[20];
sprintf(szTemp,"%d",int(temp*100.0f));
std::string sTemp = szTemp;
std::stringstream sstr2;
sstr2 << "?clientId=" << m_ClientID
<< "&clientIdChecksum=" << m_ClientIDChecksum
<< "&value=" << sTemp
<< "&random=" << GetRandom();
std::string szPostdata = sstr2.str();
std::string sURL = TOON_HOST + TOON_TEMPSET_PATH + szPostdata;
if (!HTTPClient::GET(sURL, ExtraHeaders, sResult))
{
_log.Log(LOG_ERROR, "ToonThermostat: Error setting setpoint!");
m_bDoLogin = true;
return;
}
Json::Value root;
Json::Reader jReader;
if (!jReader.parse(sResult, root))
{
_log.Log(LOG_ERROR, "ToonThermostat: Invalid data received!");
m_bDoLogin = true;
return;
}
if (root["success"].empty() == true)
{
_log.Log(LOG_ERROR, "ToonThermostat: setPoint request not successful, restarting..!");
m_bDoLogin = true;
return;
}
if (root["success"] == false)
{
_log.Log(LOG_ERROR, "ToonThermostat: setPoint request not successful, restarting..!");
m_bDoLogin = true;
return;
}
}
}
void CToonThermostat::SetProgramState(const int newState)
{
if (m_UserName.size() == 0)
return;
if (m_Password.size() == 0)
return;
std::string sResult;
std::vector<std::string> ExtraHeaders;
if (m_bDoLogin)
{
if (!Login())
return;
}
std::stringstream sstr2;
sstr2 << "?clientId=" << m_ClientID
<< "&clientIdChecksum=" << m_ClientIDChecksum
<< "&state=2"
<< "&temperatureState=" << newState
<< "&random=" << GetRandom();
std::string szPostdata = sstr2.str();
std::string sURL = TOON_HOST + TOON_CHANGE_SCHEME + szPostdata;
if (!HTTPClient::GET(sURL, ExtraHeaders, sResult))
{
_log.Log(LOG_ERROR, "ToonThermostat: Error setting Program State!");
return;
}
Json::Value root;
Json::Reader jReader;
if (!jReader.parse(sResult, root))
{
_log.Log(LOG_ERROR, "ToonThermostat: setProgramState request not successful, restarting..!");
m_bDoLogin = true;
return;
}
if (root["success"].empty() == true)
{
_log.Log(LOG_ERROR, "ToonThermostat: setProgramState request not successful, restarting..!");
m_bDoLogin = true;
return;
}
if (root["success"] == false)
{
_log.Log(LOG_ERROR, "ToonThermostat: setProgramState request not successful, restarting..!");
m_bDoLogin = true;
return;
}
}
@EdKo66
Copy link

EdKo66 commented May 11, 2017

Werkt dit nog steeds, nu Eneco toonopafstand.nl heeft uitgeschakeld? En indien ja.. hoe? Is dit een script voor Domoticz? of een hacked toon?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment