#include #include #include #include #include #include "junkers.h" extern "C" { #include "twi.h" } #define BOILER_STATE_OFFSET 0x20 #define REMOTE_STATE_OFFSET 0x90 #define BOILER_AVAILABLE_OFFSET 0x10 #define REMOTE_AVAILABLE_OFFSET 0x11 #define I2C_RAM_MAGIC_OFFSET 0xFE #define I2C_INIT_OFFSET 0xe0 #define BOILER_FLAG_BUFFEROPERATION 8 #define BOILER_SIZE 13 struct BoilerState { uint8_t vlMax2; // 0x20 uint8_t vlTemp2; // 0x21 uint8_t dlMax2; // 0x22 uint8_t dlMaxTemp2; // 0x23 uint8_t wwMax2; // 0x24 uint8_t wwTemp2; // 0x25 uint8_t error; // 0x26 uint8_t dummy1; // 0x27 uint8_t dummy2; // 0x28 uint8_t flame; // 0x29 uint8_t pump; // 0x2a uint8_t flags; // 0x2b BOILER_FLAG uint8_t dummy3; }; static BoilerState* pBoiler = (BoilerState*)(ram + BOILER_STATE_OFFSET); #define REMOTE_SIZE 16 struct RemoteState { uint8_t power; // 0x90 uint8_t vlSoll2; // 0x91 uint8_t wwSoll2; // 0x92 uint8_t dummy; // 0x93 - 1 uint8_t stopPump; // 0x94 uint8_t dummy2; // 0x95 - 1 uint8_t error; uint8_t dummy3[7]; uint8_t dummy4; uint8_t checksum; // 0x2c }; static RemoteState* pRemote = (RemoteState*)(ram + REMOTE_STATE_OFFSET); static RemoteState rxRemoteState; static void initRam() { memset(ram, 0, sizeof(ram)); ram[I2C_RAM_MAGIC_OFFSET] = 0xfc; ram[I2C_RAM_MAGIC_OFFSET + 1] = 0x03; byte initSequence[] = { 0x49, 0x46, 0x20, 0x30, 0x34, 0x2e, 0x30, 0x30 }; memcpy(ram + I2C_INIT_OFFSET, initSequence, sizeof(initSequence)); } static unsigned char crc8_table[256]; static void init_crc8() { int i,j; unsigned char crc; for (i=0; i<256; i++) { crc = i; for (j=0; j<8; j++) crc = (crc << 1) ^ ((crc & 0x80) ? 0x39 : 0); crc8_table[i] = crc & 0xFF; } } void crc8(unsigned char *crc, unsigned char m) { *crc = crc8_table[(*crc) ^ m]; *crc &= 0xFF; } void processI2c() { uint32_t m = millis(); if (!ram[REMOTE_AVAILABLE_OFFSET] && rxRemoteState.power != 0) { static uint32_t lastAvailableMillis; if (!lastAvailableMillis) { lastAvailableMillis = m; } if (m - lastAvailableMillis > 5) { lastAvailableMillis = 0; memcpy(pRemote, &rxRemoteState, sizeof(RemoteState)); if (ram[BOILER_AVAILABLE_OFFSET]) { static BoilerState oldBoilerState; BoilerState avgBoilerState; static uint16_t vlTempX; static uint16_t wwTempX; if (!vlTempX) vlTempX = pBoiler->vlTemp2 << 5; if (!wwTempX) wwTempX = pBoiler->wwTemp2 << 9; vlTempX -= (vlTempX + 16) >> 5; vlTempX += pBoiler->vlTemp2; wwTempX -= (wwTempX + 256) >> 9; wwTempX += pBoiler->wwTemp2; avgBoilerState = *pBoiler; avgBoilerState.vlTemp2 = (vlTempX + 16) >> 5; avgBoilerState.wwTemp2 = (wwTempX + 256) >> 9; static uint32_t lastUpdateMillis; if (m - lastUpdateMillis > 5000 || m - lastUpdateMillis > 500 && memcmp(&avgBoilerState, &oldBoilerState, sizeof(BoilerState))) { lastUpdateMillis = m; oldBoilerState = avgBoilerState; uint8_t buf[sizeof(BoilerState) + 1] = {0}; buf[0] = 0xf0; memcpy(buf+1, &avgBoilerState, BOILER_SIZE); radio.sendWithAck( GATEWAY, buf, BOILER_SIZE + 1); radio.setMode(SX1231_OPMODE_RECEIVER); } } ram[REMOTE_AVAILABLE_OFFSET] = 1; ram[BOILER_AVAILABLE_OFFSET] = 0; ram[0x12] = ram[0x13] = ram[0x14] = 0; ram[0x18] = 0x10; } } } FactoryRegistration RegJunkers( JUNKERS, JunkersSensor::create ); void JunkersSensor::loop() { processI2c(); uint8_t len = radio.receive( dataBuffer, SX1231_MAX_DATA_LEN ); if( len > 0) { if ((uint8_t)dataBuffer[0] == 0xf0) { memcpy(&rxRemoteState, dataBuffer+1, sizeof(RemoteState)); rxRemoteState.checksum = 0; for (uint8_t* p = (uint8_t*)&rxRemoteState; p != &rxRemoteState.checksum; p++) { crc8(&rxRemoteState.checksum,*p); } } else { checkForCommands( dataBuffer, len ); } } Sensor::loop(); } void JunkersSensor::measure() { Sensor::measure(); addMeasurement("vl",(pBoiler->vlTemp2 + 1) >> 1); addMeasurement("ww",(pBoiler->wwTemp2 + 1) >> 1); } void JunkersSensor::setup() { Sensor::setup(); tryApplySetting( "l", 1 ); init_crc8(); initRam(); twi_init(); twi_setAddress(0x50); }