mirror of
https://github.com/lumapu/ahoy.git
synced 2025-05-14 17:36:38 +02:00
* added rx channel switching
* switched to crc8 check for valid packet-payload
This commit is contained in:
parent
8f444cee2f
commit
37206847c5
11 changed files with 217 additions and 111 deletions
|
@ -70,6 +70,10 @@ class CircularBuffer {
|
||||||
return m_fill == m_size;
|
return m_fill == m_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline uint8_t getFill(void) const {
|
||||||
|
return m_fill;
|
||||||
|
}
|
||||||
|
|
||||||
/** Aquire record on front of the buffer, for writing.
|
/** Aquire record on front of the buffer, for writing.
|
||||||
* After filling the record, it has to be pushed to actually
|
* After filling the record, it has to be pushed to actually
|
||||||
* add it to the buffer.
|
* add it to the buffer.
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "html/h/index_html.h"
|
#include "html/h/index_html.h"
|
||||||
#include "html/h/setup_html.h"
|
#include "html/h/setup_html.h"
|
||||||
#include "html/h/hoymiles_html.h"
|
#include "html/h/hoymiles_html.h"
|
||||||
|
#include "html/h/debug_html.h"
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -16,6 +17,7 @@ app::app() : Main() {
|
||||||
mMqttActive = false;
|
mMqttActive = false;
|
||||||
|
|
||||||
mTicker = 0;
|
mTicker = 0;
|
||||||
|
mRxTicker = 0;
|
||||||
|
|
||||||
mShowRebootRequest = false;
|
mShowRebootRequest = false;
|
||||||
|
|
||||||
|
@ -26,6 +28,8 @@ app::app() : Main() {
|
||||||
//memset(mChannelStat, 0, sizeof(uint32_t) * 4);
|
//memset(mChannelStat, 0, sizeof(uint32_t) * 4);
|
||||||
|
|
||||||
mSys = new HmSystemType();
|
mSys = new HmSystemType();
|
||||||
|
|
||||||
|
memset(mPayload, 0, ((MAX_RF_PAYLOAD_SIZE-11) * MAX_NUM_PAC_PER_PAYLOAD));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,6 +50,7 @@ void app::setup(uint32_t timeout) {
|
||||||
mWeb->on("/cmdstat", std::bind(&app::showStatistics, this));
|
mWeb->on("/cmdstat", std::bind(&app::showStatistics, this));
|
||||||
mWeb->on("/hoymiles", std::bind(&app::showHoymiles, this));
|
mWeb->on("/hoymiles", std::bind(&app::showHoymiles, this));
|
||||||
mWeb->on("/livedata", std::bind(&app::showLiveData, this));
|
mWeb->on("/livedata", std::bind(&app::showLiveData, this));
|
||||||
|
mWeb->on("/debug", std::bind(&app::showDebug, this));
|
||||||
|
|
||||||
if(mSettingsValid) {
|
if(mSettingsValid) {
|
||||||
uint64_t invSerial;
|
uint64_t invSerial;
|
||||||
|
@ -62,10 +67,11 @@ void app::setup(uint32_t timeout) {
|
||||||
DPRINTLN("add inverter: " + String(invName) + ", SN: " + String(invSerial, HEX) + ", type: " + String(invType));
|
DPRINTLN("add inverter: " + String(invName) + ", SN: " + String(invSerial, HEX) + ", type: " + String(invType));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mEep->read(ADDR_INV_INTERVAL, &mSendInterval);
|
// @TODO reenable
|
||||||
if(mSendInterval < 1)
|
//mEep->read(ADDR_INV_INTERVAL, &mSendInterval);
|
||||||
mSendInterval = 1;
|
//if(mSendInterval < 5)
|
||||||
|
// mSendInterval = 5;
|
||||||
|
mSendInterval = 5;
|
||||||
|
|
||||||
// pinout
|
// pinout
|
||||||
mEep->read(ADDR_PINOUT, &mSys->Radio.pinCs);
|
mEep->read(ADDR_PINOUT, &mSys->Radio.pinCs);
|
||||||
|
@ -134,26 +140,31 @@ void app::setup(uint32_t timeout) {
|
||||||
void app::loop(void) {
|
void app::loop(void) {
|
||||||
Main::loop();
|
Main::loop();
|
||||||
|
|
||||||
|
if(checkTicker(&mRxTicker, 5)) {
|
||||||
|
mSys->Radio.switchRxCh();
|
||||||
if(!mSys->BufCtrl.empty()) {
|
if(!mSys->BufCtrl.empty()) {
|
||||||
uint8_t len, rptCnt;
|
uint8_t len, rptCnt;
|
||||||
packet_t *p = mSys->BufCtrl.getBack();
|
packet_t *p = mSys->BufCtrl.getBack();
|
||||||
if(mSerialDebug)
|
|
||||||
mSys->Radio.dumpBuf("RAW ", p->packet, MAX_RF_PAYLOAD_SIZE);
|
|
||||||
|
|
||||||
if(mSys->Radio.checkCrc(p->packet, &len, &rptCnt)) {
|
//if(mSerialDebug)
|
||||||
|
// mSys->Radio.dumpBuf("RAW ", p->packet, MAX_RF_PAYLOAD_SIZE);
|
||||||
|
|
||||||
|
if(mSys->Radio.checkPaketCrc(p->packet, &len, &rptCnt, p->rxCh)) {
|
||||||
// process buffer only on first occurrence
|
// process buffer only on first occurrence
|
||||||
if((0 != len) && (0 == rptCnt)) {
|
if((0 != len) && (0 == rptCnt)) {
|
||||||
uint8_t *cmd = &p->packet[11];
|
uint8_t *cmd = &p->packet[9];
|
||||||
//DPRINTLN("CMD " + String(*cmd, HEX));
|
//DPRINTLN("CMD " + String(*cmd, HEX));
|
||||||
//mSys->Radio.dumpBuf("Payload ", p->packet, len);
|
if(mSerialDebug)
|
||||||
|
mSys->Radio.dumpBuf("Payload ", p->packet, len);
|
||||||
|
|
||||||
Inverter<> *iv = mSys->findInverter(&p->packet[3]);
|
Inverter<> *iv = mSys->findInverter(&p->packet[1]);
|
||||||
if(NULL != iv) {
|
if(NULL != iv) {
|
||||||
for(uint8_t i = 0; i < iv->listLen; i++) {
|
for(uint8_t i = 0; i < iv->listLen; i++) {
|
||||||
if(iv->assign[i].cmdId == *cmd)
|
if(iv->assign[i].cmdId == *cmd)
|
||||||
iv->addValue(i, &p->packet[11]);
|
iv->addValue(i, &p->packet[9]);
|
||||||
}
|
}
|
||||||
iv->doCalculations();
|
iv->doCalculations();
|
||||||
|
//memcpy(mPayload[(*cmd & 0x7F) - 1], &p->packet[9], MAX_RF_PAYLOAD_SIZE - 11);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(*cmd == 0x01) mCmds[0]++;
|
if(*cmd == 0x01) mCmds[0]++;
|
||||||
|
@ -164,20 +175,18 @@ void app::loop(void) {
|
||||||
else if(*cmd == 0x83) mCmds[5]++;
|
else if(*cmd == 0x83) mCmds[5]++;
|
||||||
else if(*cmd == 0x84) mCmds[6]++;
|
else if(*cmd == 0x84) mCmds[6]++;
|
||||||
else mCmds[7]++;
|
else mCmds[7]++;
|
||||||
|
|
||||||
/*if(p->sendCh == 23) mChannelStat[0]++;
|
|
||||||
else if(p->sendCh == 40) mChannelStat[1]++;
|
|
||||||
else if(p->sendCh == 61) mChannelStat[2]++;
|
|
||||||
else mChannelStat[3]++;*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mSys->BufCtrl.popBack();
|
mSys->BufCtrl.popBack();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(checkTicker(&mTicker, 1000)) {
|
if(checkTicker(&mTicker, 1000)) {
|
||||||
if(++mSendTicker >= mSendInterval) {
|
if(++mSendTicker >= mSendInterval) {
|
||||||
mSendTicker = 0;
|
mSendTicker = 0;
|
||||||
|
|
||||||
|
if(!mSys->BufCtrl.empty())
|
||||||
|
DPRINTLN("recbuf not empty! #" + String(mSys->BufCtrl.getFill()));
|
||||||
Inverter<> *inv;
|
Inverter<> *inv;
|
||||||
for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i ++) {
|
for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i ++) {
|
||||||
inv = mSys->getInverterByPos(i);
|
inv = mSys->getInverterByPos(i);
|
||||||
|
@ -504,6 +513,36 @@ void app::showLiveData(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void app::showDebug() {
|
||||||
|
if(mWeb->args() > 0) {
|
||||||
|
/*String html;
|
||||||
|
|
||||||
|
for(uint8_t i = 0; i < MAX_NUM_PAC_PER_PAYLOAD; i ++) {
|
||||||
|
for(uint8_t j = 0; j < (MAX_RF_PAYLOAD_SIZE- 11); j++) {
|
||||||
|
if(mPayload[i][j] < 0x10)
|
||||||
|
html += "0";
|
||||||
|
html += String(mPayload[i][j], HEX) + " ";
|
||||||
|
}
|
||||||
|
html += "\n";
|
||||||
|
}
|
||||||
|
html += "CMDS: ";
|
||||||
|
for(uint8_t i = 0; i < DBG_CMD_LIST_LEN; i ++) {
|
||||||
|
html += String(mCmds[i]) + String(" ");
|
||||||
|
}
|
||||||
|
html += "\n------------------";*/
|
||||||
|
|
||||||
|
mWeb->send(200, "text/plain", "na");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
String html = FPSTR(debug_html);
|
||||||
|
html.replace("{DEVICE}", mDeviceName);
|
||||||
|
html.replace("{VERSION}", mVersion);
|
||||||
|
mWeb->send(200, "text/html", html);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void app::saveValues(bool webSend = true) {
|
void app::saveValues(bool webSend = true) {
|
||||||
Main::saveValues(false); // general configuration
|
Main::saveValues(false); // general configuration
|
||||||
|
|
|
@ -47,6 +47,7 @@ class app : public Main {
|
||||||
void showStatistics(void);
|
void showStatistics(void);
|
||||||
void showHoymiles(void);
|
void showHoymiles(void);
|
||||||
void showLiveData(void);
|
void showLiveData(void);
|
||||||
|
void showDebug(void);
|
||||||
|
|
||||||
void saveValues(bool webSend);
|
void saveValues(bool webSend);
|
||||||
void updateCrc(void);
|
void updateCrc(void);
|
||||||
|
@ -82,6 +83,8 @@ class app : public Main {
|
||||||
bool mSerialValues;
|
bool mSerialValues;
|
||||||
bool mSerialDebug;
|
bool mSerialDebug;
|
||||||
|
|
||||||
|
uint32_t mRxTicker;
|
||||||
|
|
||||||
// mqtt
|
// mqtt
|
||||||
mqtt mMqtt;
|
mqtt mMqtt;
|
||||||
uint16_t mMqttTicker;
|
uint16_t mMqttTicker;
|
||||||
|
@ -89,6 +92,8 @@ class app : public Main {
|
||||||
bool mMqttActive;
|
bool mMqttActive;
|
||||||
uint16_t mSerialTicker;
|
uint16_t mSerialTicker;
|
||||||
uint16_t mSerialInterval;
|
uint16_t mSerialInterval;
|
||||||
|
|
||||||
|
uint8_t mPayload[MAX_NUM_PAC_PER_PAYLOAD][MAX_RF_PAYLOAD_SIZE-11];
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /*__APP_H__*/
|
#endif /*__APP_H__*/
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
// CONFIGURATION - COMPILE TIME
|
// CONFIGURATION - COMPILE TIME
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
// time in seconds how long the station info (ssid + pwd) will be tried
|
// time in seconds how long the station info (ssid + pwd) will be tried
|
||||||
#define WIFI_TRY_CONNECT_TIME 15
|
#define WIFI_TRY_CONNECT_TIME 30
|
||||||
|
|
||||||
// time during the ESP will act as access point on connection failure (to
|
// time during the ESP will act as access point on connection failure (to
|
||||||
// station) in seconds
|
// station) in seconds
|
||||||
|
@ -36,7 +36,9 @@
|
||||||
#define MAX_NAME_LENGTH 16
|
#define MAX_NAME_LENGTH 16
|
||||||
|
|
||||||
// maximum buffer length of packet received / sent to RF24 module
|
// maximum buffer length of packet received / sent to RF24 module
|
||||||
#define MAX_RF_PAYLOAD_SIZE 64
|
#define MAX_RF_PAYLOAD_SIZE 32
|
||||||
|
|
||||||
|
#define MAX_NUM_PAC_PER_PAYLOAD 4
|
||||||
|
|
||||||
// changes the style of "/setup" page, visualized = nicer
|
// changes the style of "/setup" page, visualized = nicer
|
||||||
#define LIVEDATA_VISUALIZED
|
#define LIVEDATA_VISUALIZED
|
||||||
|
|
|
@ -16,12 +16,12 @@
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
#define VERSION_MAJOR 0
|
#define VERSION_MAJOR 0
|
||||||
#define VERSION_MINOR 3
|
#define VERSION_MINOR 3
|
||||||
#define VERSION_PATCH 6
|
#define VERSION_PATCH 7
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t sendCh;
|
uint8_t rxCh;
|
||||||
uint8_t packet[MAX_RF_PAYLOAD_SIZE];
|
uint8_t packet[MAX_RF_PAYLOAD_SIZE];
|
||||||
} packet_t;
|
} packet_t;
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#define DTU_RADIO_ID ((uint64_t)0x1234567801ULL)
|
#define DTU_RADIO_ID ((uint64_t)0x1234567801ULL)
|
||||||
#define DUMMY_RADIO_ID ((uint64_t)0xDEADBEEF01ULL)
|
#define DUMMY_RADIO_ID ((uint64_t)0xDEADBEEF01ULL)
|
||||||
|
|
||||||
|
#define RX_LOOP_CNT 400
|
||||||
|
|
||||||
const char* const rf24AmpPower[] = {"MIN", "LOW", "HIGH", "MAX"};
|
const char* const rf24AmpPower[] = {"MIN", "LOW", "HIGH", "MAX"};
|
||||||
|
|
||||||
|
@ -47,13 +48,17 @@ template <uint8_t CE_PIN, uint8_t CS_PIN, uint8_t IRQ_PIN, class BUFFER, uint64_
|
||||||
class HmRadio {
|
class HmRadio {
|
||||||
public:
|
public:
|
||||||
HmRadio() : mNrf24(CE_PIN, CS_PIN, SPI_SPEED) {
|
HmRadio() : mNrf24(CE_PIN, CS_PIN, SPI_SPEED) {
|
||||||
mChanOut[0] = 23;
|
mTxChLst[0] = 40;
|
||||||
mChanOut[1] = 40;
|
//mTxChIdx = 1;
|
||||||
mChanOut[2] = 61;
|
|
||||||
mChanOut[3] = 75;
|
|
||||||
mChanIdx = 1;
|
|
||||||
|
|
||||||
calcDtuCrc();
|
mRxChLst[0] = 3;
|
||||||
|
mRxChLst[1] = 23;
|
||||||
|
mRxChLst[2] = 61;
|
||||||
|
mRxChLst[3] = 75;
|
||||||
|
mRxChIdx = 0;
|
||||||
|
mRxLoopCnt = RX_LOOP_CNT;
|
||||||
|
|
||||||
|
//calcDtuCrc();
|
||||||
|
|
||||||
pinCs = CS_PIN;
|
pinCs = CS_PIN;
|
||||||
pinCe = CE_PIN;
|
pinCe = CE_PIN;
|
||||||
|
@ -65,7 +70,6 @@ class HmRadio {
|
||||||
~HmRadio() {}
|
~HmRadio() {}
|
||||||
|
|
||||||
void setup(BUFFER *ctrl) {
|
void setup(BUFFER *ctrl) {
|
||||||
//DPRINTLN("HmRadio::setup, pins: " + String(pinCs) + ", " + String(pinCe) + ", " + String(pinIrq));
|
|
||||||
pinMode(pinIrq, INPUT_PULLUP);
|
pinMode(pinIrq, INPUT_PULLUP);
|
||||||
|
|
||||||
mBufCtrl = ctrl;
|
mBufCtrl = ctrl;
|
||||||
|
@ -91,7 +95,7 @@ class HmRadio {
|
||||||
DPRINTLN("Radio Config:");
|
DPRINTLN("Radio Config:");
|
||||||
mNrf24.printPrettyDetails();
|
mNrf24.printPrettyDetails();
|
||||||
|
|
||||||
mSendChannel = getDefaultChannel();
|
mTxCh = getDefaultChannel();
|
||||||
|
|
||||||
if(!mNrf24.isChipConnected()) {
|
if(!mNrf24.isChipConnected()) {
|
||||||
DPRINTLN("WARNING! your NRF24 module can't be reached, check the wiring");
|
DPRINTLN("WARNING! your NRF24 module can't be reached, check the wiring");
|
||||||
|
@ -107,7 +111,7 @@ class HmRadio {
|
||||||
if(!mBufCtrl->full()) {
|
if(!mBufCtrl->full()) {
|
||||||
p = mBufCtrl->getFront();
|
p = mBufCtrl->getFront();
|
||||||
memset(p->packet, 0xcc, MAX_RF_PAYLOAD_SIZE);
|
memset(p->packet, 0xcc, MAX_RF_PAYLOAD_SIZE);
|
||||||
p->sendCh = mSendChannel;
|
p->rxCh = mRxChIdx;
|
||||||
len = mNrf24.getPayloadSize();
|
len = mNrf24.getPayloadSize();
|
||||||
if(len > MAX_RF_PAYLOAD_SIZE)
|
if(len > MAX_RF_PAYLOAD_SIZE)
|
||||||
len = MAX_RF_PAYLOAD_SIZE;
|
len = MAX_RF_PAYLOAD_SIZE;
|
||||||
|
@ -125,53 +129,55 @@ class HmRadio {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t getDefaultChannel(void) {
|
uint8_t getDefaultChannel(void) {
|
||||||
return mChanOut[2];
|
return mTxChLst[0];
|
||||||
}
|
}
|
||||||
uint8_t getLastChannel(void) {
|
/*uint8_t getLastChannel(void) {
|
||||||
return mChanOut[mChanIdx];
|
return mTxChLst[mTxChIdx];
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t getNxtChannel(void) {
|
uint8_t getNxtChannel(void) {
|
||||||
if(++mChanIdx >= 4)
|
if(++mTxChIdx >= 4)
|
||||||
mChanIdx = 0;
|
mTxChIdx = 0;
|
||||||
return mChanOut[mChanIdx];
|
return mTxChLst[mTxChIdx];
|
||||||
}
|
}*/
|
||||||
|
|
||||||
void sendTimePacket(uint64_t invId, uint32_t ts) {
|
void sendTimePacket(uint64_t invId, uint32_t ts) {
|
||||||
sendCmdPacket(invId, 0x15, 0x80, false);
|
sendCmdPacket(invId, 0x15, 0x80, false);
|
||||||
mSendBuf[10] = 0x0b; // cid
|
mTxBuf[10] = 0x0b; // cid
|
||||||
mSendBuf[11] = 0x00;
|
mTxBuf[11] = 0x00;
|
||||||
CP_U32_LittleEndian(&mSendBuf[12], ts);
|
CP_U32_LittleEndian(&mTxBuf[12], ts);
|
||||||
mSendBuf[19] = 0x05;
|
mTxBuf[19] = 0x05;
|
||||||
|
|
||||||
uint16_t crc = crc16(&mSendBuf[10], 14);
|
uint16_t crc = crc16(&mTxBuf[10], 14);
|
||||||
mSendBuf[24] = (crc >> 8) & 0xff;
|
mTxBuf[24] = (crc >> 8) & 0xff;
|
||||||
mSendBuf[25] = (crc ) & 0xff;
|
mTxBuf[25] = (crc ) & 0xff;
|
||||||
mSendBuf[26] = crc8(mSendBuf, 26);
|
mTxBuf[26] = crc8(mTxBuf, 26);
|
||||||
|
|
||||||
sendPacket(invId, mSendBuf, 27);
|
sendPacket(invId, mTxBuf, 27, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendCmdPacket(uint64_t invId, uint8_t mid, uint8_t cmd, bool calcCrc = true) {
|
void sendCmdPacket(uint64_t invId, uint8_t mid, uint8_t cmd, bool calcCrc = true) {
|
||||||
memset(mSendBuf, 0, MAX_RF_PAYLOAD_SIZE);
|
memset(mTxBuf, 0, MAX_RF_PAYLOAD_SIZE);
|
||||||
mSendBuf[0] = mid; // message id
|
mTxBuf[0] = mid; // message id
|
||||||
CP_U32_BigEndian(&mSendBuf[1], (invId >> 8));
|
CP_U32_BigEndian(&mTxBuf[1], (invId >> 8));
|
||||||
CP_U32_BigEndian(&mSendBuf[5], (DTU_ID >> 8));
|
CP_U32_BigEndian(&mTxBuf[5], (DTU_ID >> 8));
|
||||||
mSendBuf[9] = cmd;
|
mTxBuf[9] = cmd;
|
||||||
if(calcCrc) {
|
if(calcCrc) {
|
||||||
mSendBuf[10] = crc8(mSendBuf, 10);
|
mTxBuf[10] = crc8(mTxBuf, 10);
|
||||||
sendPacket(invId, mSendBuf, 11);
|
sendPacket(invId, mTxBuf, 11, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool checkCrc(uint8_t buf[], uint8_t *len, uint8_t *rptCnt) {
|
bool checkPaketCrc(uint8_t buf[], uint8_t *len, uint8_t *rptCnt, uint8_t rxCh) {
|
||||||
*len = (buf[0] >> 2);
|
*len = (buf[0] >> 2);
|
||||||
for (int16_t i = MAX_RF_PAYLOAD_SIZE - 1; i >= 0; i--) {
|
if(*len > (MAX_RF_PAYLOAD_SIZE - 2))
|
||||||
buf[i] = ((buf[i] >> 7) | ((i > 0) ? (buf[i-1] << 1) : 0x00));
|
*len = MAX_RF_PAYLOAD_SIZE - 2;
|
||||||
|
for(uint8_t i = 1; i < (*len + 1); i++) {
|
||||||
|
buf[i-1] = (buf[i] << 1) | (buf[i+1] >> 7);
|
||||||
}
|
}
|
||||||
uint16_t crc = crc16nrf24(buf, BIT_CNT(*len + 2), 7, mDtuIdCrc);
|
|
||||||
|
|
||||||
bool valid = (crc == ((buf[*len+2] << 8) | (buf[*len+3])));
|
uint8_t crc = crc8(buf, *len-1);
|
||||||
|
bool valid = (crc == buf[*len-1]);
|
||||||
|
|
||||||
if(valid) {
|
if(valid) {
|
||||||
if(mLastCrc == crc)
|
if(mLastCrc == crc)
|
||||||
|
@ -181,16 +187,34 @@ class HmRadio {
|
||||||
*rptCnt = 0;
|
*rptCnt = 0;
|
||||||
mLastCrc = crc;
|
mLastCrc = crc;
|
||||||
}
|
}
|
||||||
|
mRxStat[(buf[9] & 0x7F)-1]++;
|
||||||
|
mRxChStat[(buf[9] & 0x7F)-1][rxCh & 0x7]++;
|
||||||
}
|
}
|
||||||
|
/*else {
|
||||||
|
DPRINT("CRC wrong: ");
|
||||||
|
DHEX(crc);
|
||||||
|
DPRINT(" != ");
|
||||||
|
DHEX(buf[*len-1]);
|
||||||
|
DPRINTLN("");
|
||||||
|
}*/
|
||||||
|
|
||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool switchRxCh(uint8_t addLoop = 0) {
|
||||||
|
mRxLoopCnt += addLoop;
|
||||||
|
if(mRxLoopCnt != 0) {
|
||||||
|
mRxLoopCnt--;
|
||||||
|
mNrf24.stopListening();
|
||||||
|
mNrf24.setChannel(getRxNxtChannel());
|
||||||
|
mNrf24.startListening();
|
||||||
|
}
|
||||||
|
return (0 == mRxLoopCnt); // receive finished
|
||||||
|
}
|
||||||
|
|
||||||
void dumpBuf(const char *info, uint8_t buf[], uint8_t len) {
|
void dumpBuf(const char *info, uint8_t buf[], uint8_t len) {
|
||||||
DPRINT(String(info));
|
DPRINT(String(info));
|
||||||
for(uint8_t i = 0; i < len; i++) {
|
for(uint8_t i = 0; i < len; i++) {
|
||||||
if(buf[i] < 10)
|
|
||||||
DPRINT("0");
|
|
||||||
DHEX(buf[i]);
|
DHEX(buf[i]);
|
||||||
DPRINT(" ");
|
DPRINT(" ");
|
||||||
}
|
}
|
||||||
|
@ -209,26 +233,41 @@ class HmRadio {
|
||||||
uint32_t mSendCnt;
|
uint32_t mSendCnt;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void sendPacket(uint64_t invId, uint8_t buf[], uint8_t len) {
|
void sendPacket(uint64_t invId, uint8_t buf[], uint8_t len, bool clear=false) {
|
||||||
//DPRINTLN("sent packet: #" + String(mSendCnt));
|
//DPRINTLN("sent packet: #" + String(mSendCnt));
|
||||||
//dumpBuf("SEN ", buf, len);
|
//dumpBuf("SEN ", buf, len);
|
||||||
|
|
||||||
DISABLE_IRQ;
|
DISABLE_IRQ;
|
||||||
mNrf24.stopListening();
|
mNrf24.stopListening();
|
||||||
|
|
||||||
#ifdef CHANNEL_HOP
|
if(clear) {
|
||||||
mSendChannel = getNxtChannel();
|
uint8_t cnt = 4;
|
||||||
#else
|
for(uint8_t i = 0; i < 4; i ++) {
|
||||||
mSendChannel = getDefaultChannel();
|
DPRINT(String(mRxStat[i]) + " (");
|
||||||
#endif
|
for(uint8_t j = 0; j < 4; j++) {
|
||||||
mNrf24.setChannel(mSendChannel);
|
DPRINT(String(mRxChStat[i][j]));
|
||||||
//DPRINTLN("CH: " + String(mSendChannel));
|
}
|
||||||
|
DPRINT(") ");
|
||||||
|
if(0 != mRxStat[i])
|
||||||
|
cnt--;
|
||||||
|
}
|
||||||
|
if(cnt == 0)
|
||||||
|
DPRINTLN(" -> all");
|
||||||
|
else
|
||||||
|
DPRINTLN(" -> missing: " + String(cnt));
|
||||||
|
memset(mRxStat, 0, 4);
|
||||||
|
memset(mRxChStat, 0, 4*8);
|
||||||
|
mRxLoopCnt = RX_LOOP_CNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
mTxCh = getDefaultChannel();
|
||||||
|
mNrf24.setChannel(mTxCh);
|
||||||
|
|
||||||
mNrf24.openWritingPipe(invId); // TODO: deprecated
|
mNrf24.openWritingPipe(invId); // TODO: deprecated
|
||||||
mNrf24.setCRCLength(RF24_CRC_16);
|
mNrf24.setCRCLength(RF24_CRC_16);
|
||||||
mNrf24.enableDynamicPayloads();
|
mNrf24.enableDynamicPayloads();
|
||||||
mNrf24.setAutoAck(true);
|
mNrf24.setAutoAck(true);
|
||||||
mNrf24.setRetries(3, 15);
|
mNrf24.setRetries(3, 15); // 3*250us and 15 loops -> 11.25ms
|
||||||
|
|
||||||
mNrf24.write(buf, len);
|
mNrf24.write(buf, len);
|
||||||
|
|
||||||
|
@ -240,14 +279,21 @@ class HmRadio {
|
||||||
mNrf24.disableDynamicPayloads();
|
mNrf24.disableDynamicPayloads();
|
||||||
mNrf24.setCRCLength(RF24_CRC_DISABLED);
|
mNrf24.setCRCLength(RF24_CRC_DISABLED);
|
||||||
|
|
||||||
mNrf24.setChannel(DEFAULT_RECV_CHANNEL);
|
mRxChIdx = 0;
|
||||||
|
mNrf24.setChannel(mRxChLst[mRxChIdx]);
|
||||||
mNrf24.startListening();
|
mNrf24.startListening();
|
||||||
|
|
||||||
RESTORE_IRQ;
|
RESTORE_IRQ;
|
||||||
mSendCnt++;
|
mSendCnt++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void calcDtuCrc(void) {
|
uint8_t getRxNxtChannel(void) {
|
||||||
|
if(++mRxChIdx >= 4)
|
||||||
|
mRxChIdx = 0;
|
||||||
|
return mRxChLst[mRxChIdx];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*void calcDtuCrc(void) {
|
||||||
uint64_t addr = DTU_RADIO_ID;
|
uint64_t addr = DTU_RADIO_ID;
|
||||||
uint8_t tmp[5];
|
uint8_t tmp[5];
|
||||||
for(int8_t i = 4; i >= 0; i--) {
|
for(int8_t i = 4; i >= 0; i--) {
|
||||||
|
@ -255,18 +301,26 @@ class HmRadio {
|
||||||
addr >>= 8;
|
addr >>= 8;
|
||||||
}
|
}
|
||||||
mDtuIdCrc = crc16nrf24(tmp, BIT_CNT(5));
|
mDtuIdCrc = crc16nrf24(tmp, BIT_CNT(5));
|
||||||
}
|
}*/
|
||||||
|
|
||||||
uint8_t mChanOut[4];
|
uint8_t mTxCh;
|
||||||
uint8_t mChanIdx;
|
uint8_t mTxChLst[1];
|
||||||
uint16_t mDtuIdCrc;
|
//uint8_t mTxChIdx;
|
||||||
|
|
||||||
|
uint8_t mRxChLst[4];
|
||||||
|
uint8_t mRxChIdx;
|
||||||
|
uint8_t mRxStat[4];
|
||||||
|
uint8_t mRxChStat[4][8];
|
||||||
|
uint16_t mRxLoopCnt;
|
||||||
|
|
||||||
|
//uint16_t mDtuIdCrc;
|
||||||
uint16_t mLastCrc;
|
uint16_t mLastCrc;
|
||||||
uint8_t mRptCnt;
|
uint8_t mRptCnt;
|
||||||
|
|
||||||
RF24 mNrf24;
|
RF24 mNrf24;
|
||||||
uint8_t mSendChannel;
|
|
||||||
BUFFER *mBufCtrl;
|
BUFFER *mBufCtrl;
|
||||||
uint8_t mSendBuf[MAX_RF_PAYLOAD_SIZE];
|
uint8_t mTxBuf[MAX_RF_PAYLOAD_SIZE];
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /*__RADIO_H__*/
|
#endif /*__RADIO_H__*/
|
||||||
|
|
|
@ -15,14 +15,16 @@ def convert2Header(inFile):
|
||||||
data = re.sub(r"(\;|\}|\:|\{)\s+", r'\1', data) # whitespaces inner css
|
data = re.sub(r"(\;|\}|\:|\{)\s+", r'\1', data) # whitespaces inner css
|
||||||
|
|
||||||
define = inFile.split(".")[0].upper()
|
define = inFile.split(".")[0].upper()
|
||||||
|
define2 = inFile.split(".")[1].upper()
|
||||||
f = open(outName, "w")
|
f = open(outName, "w")
|
||||||
f.write("#ifndef __{}_H__\n".format(define))
|
f.write("#ifndef __{}_{}_H__\n".format(define, define2))
|
||||||
f.write("#define __{}_H__\n".format(define))
|
f.write("#define __{}_{}_H__\n".format(define, define2))
|
||||||
f.write("const char {}[] PROGMEM = \"{}\";\n".format(inFile.replace(".", "_"), data))
|
f.write("const char {}[] PROGMEM = \"{}\";\n".format(inFile.replace(".", "_"), data))
|
||||||
f.write("#endif /*__{}_H__*/\n".format(define))
|
f.write("#endif /*__{}_{}_H__*/\n".format(define, define2))
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
convert2Header("index.html")
|
convert2Header("index.html")
|
||||||
convert2Header("setup.html")
|
convert2Header("setup.html")
|
||||||
convert2Header("hoymiles.html")
|
convert2Header("hoymiles.html")
|
||||||
convert2Header("style.css")
|
convert2Header("style.css")
|
||||||
|
convert2Header("debug.html")
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#ifndef __HOYMILES_H__
|
#ifndef __HOYMILES_HTML_H__
|
||||||
#define __HOYMILES_H__
|
#define __HOYMILES_HTML_H__
|
||||||
const char hoymiles_html[] PROGMEM = "<!doctype html><html><head><title>Index - {DEVICE}</title><link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\"/><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><script type=\"text/javascript\">getAjax('/livedata', 'livedata');window.setInterval(\"getAjax('/livedata', 'livedata')\", 10000);function getAjax(url, resid) {var http = null;http = new XMLHttpRequest();if(http != null) {http.open(\"GET\", url, true);http.onreadystatechange = print;http.send(null);}function print() {if(http.readyState == 4) {document.getElementById(resid).innerHTML = http.responseText;}}}</script><style type=\"text/css\"></style></head><body><h1>AHOY - {DEVICE}</h1><div id=\"content\" class=\"content\"><div id=\"livedata\"></div><p>Every 10 seconds the values are updated</p></div><div id=\"footer\"><p class=\"left\">© 2022</p><p class=\"left\"><a href=\"/\">Home</a></p><p class=\"right\">AHOY :: {VERSION}</p></div></body></html>";
|
const char hoymiles_html[] PROGMEM = "<!doctype html><html><head><title>Index - {DEVICE}</title><link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\"/><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><script type=\"text/javascript\">getAjax('/livedata', 'livedata');window.setInterval(\"getAjax('/livedata', 'livedata')\", 10000);function getAjax(url, resid) {var http = null;http = new XMLHttpRequest();if(http != null) {http.open(\"GET\", url, true);http.onreadystatechange = print;http.send(null);}function print() {if(http.readyState == 4) {document.getElementById(resid).innerHTML = http.responseText;}}}</script><style type=\"text/css\"></style></head><body><h1>AHOY - {DEVICE}</h1><div id=\"content\" class=\"content\"><div id=\"livedata\"></div><p>Every 10 seconds the values are updated</p></div><div id=\"footer\"><p class=\"left\">© 2022</p><p class=\"left\"><a href=\"/\">Home</a></p><p class=\"right\">AHOY :: {VERSION}</p></div></body></html>";
|
||||||
#endif /*__HOYMILES_H__*/
|
#endif /*__HOYMILES_HTML_H__*/
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#ifndef __INDEX_H__
|
#ifndef __INDEX_HTML_H__
|
||||||
#define __INDEX_H__
|
#define __INDEX_HTML_H__
|
||||||
const char index_html[] PROGMEM = "<!doctype html><html><head><title>Index - {DEVICE}</title><link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\"/><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><script type=\"text/javascript\">window.setInterval(\"getAjax('/uptime', 'uptime')\", 1000);window.setInterval(\"getAjax('/time', 'time')\", 1000);window.setInterval(\"getAjax('/cmdstat', 'cmds')\", 2000);function getAjax(url, resid) {var http = null;http = new XMLHttpRequest();if(http != null) {http.open(\"GET\", url, true);http.onreadystatechange = print;http.send(null);}function print() {if(http.readyState == 4) {document.getElementById(resid).innerHTML = http.responseText;}}}</script></head><body><h1>AHOY - {DEVICE}</h1><div id=\"content\" class=\"content\"><p><a href=\"/hoymiles\">Visualization</a><br/><br/><a href=\"/setup\">Setup</a><br/></p><p><span class=\"des\">Uptime: </span><span id=\"uptime\"></span></p><p><span class=\"des\">Time: </span><span id=\"time\"></span></p><p><span class=\"des\">Statistics: </span><pre id=\"cmds\"></pre></p><div id=\"note\">This project was started from <a href=\"https://www.mikrocontroller.net/topic/525778\" target=\"_blank\">this discussion. (Mikrocontroller.net)</a><br/>New updates can be found on Github: <a href=\"https://github.com/grindylow/ahoy\" target=\"_blank\">https://github.com/grindylow/ahoy</a><br/><br/>Please report issues using the feature provided by Github. </div></div><div id=\"footer\"><p class=\"left\">© 2022</p><p class=\"left\"><a href=\"/update\">Update Firmware</a></p><p class=\"right\">AHOY :: {VERSION}</p><p class=\"right\"><a href=\"/reboot\">Reboot</a></p></div></body></html>";
|
const char index_html[] PROGMEM = "<!doctype html><html><head><title>Index - {DEVICE}</title><link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\"/><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><script type=\"text/javascript\">window.setInterval(\"getAjax('/uptime', 'uptime')\", 1000);window.setInterval(\"getAjax('/time', 'time')\", 1000);window.setInterval(\"getAjax('/cmdstat', 'cmds')\", 2000);function getAjax(url, resid) {var http = null;http = new XMLHttpRequest();if(http != null) {http.open(\"GET\", url, true);http.onreadystatechange = print;http.send(null);}function print() {if(http.readyState == 4) {document.getElementById(resid).innerHTML = http.responseText;}}}</script></head><body><h1>AHOY - {DEVICE}</h1><div id=\"content\" class=\"content\"><p><a href=\"/hoymiles\">Visualization</a><br/><br/><a href=\"/setup\">Setup</a><br/></p><p><span class=\"des\">Uptime: </span><span id=\"uptime\"></span></p><p><span class=\"des\">Time: </span><span id=\"time\"></span></p><p><span class=\"des\">Statistics: </span><pre id=\"cmds\"></pre></p><div id=\"note\">This project was started from <a href=\"https://www.mikrocontroller.net/topic/525778\" target=\"_blank\">this discussion. (Mikrocontroller.net)</a><br/>New updates can be found on Github: <a href=\"https://github.com/grindylow/ahoy\" target=\"_blank\">https://github.com/grindylow/ahoy</a><br/><br/>Please report issues using the feature provided by Github. </div></div><div id=\"footer\"><p class=\"left\">© 2022</p><p class=\"left\"><a href=\"/update\">Update Firmware</a></p><p class=\"right\">AHOY :: {VERSION}</p><p class=\"right\"><a href=\"/reboot\">Reboot</a></p></div></body></html>";
|
||||||
#endif /*__INDEX_H__*/
|
#endif /*__INDEX_HTML_H__*/
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#ifndef __SETUP_H__
|
#ifndef __SETUP_HTML_H__
|
||||||
#define __SETUP_H__
|
#define __SETUP_HTML_H__
|
||||||
const char setup_html[] PROGMEM = "<!doctype html><html><head><title>Setup - {DEVICE}</title><link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\"/><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"></head><body><h1>Setup</h1><div id=\"setup\" class=\"content\"><div id=\"content\"><p>Enter the credentials to your prefered WiFi station. After rebooting the device tries to connect with this information. </p><form method=\"post\" action=\"{IP}/save\"><p class=\"des\">WiFi</p><label for=\"ssid\">SSID</label><input type=\"text\" class=\"text\" name=\"ssid\" value=\"{SSID}\"/><label for=\"pwd\">Password</label><input type=\"password\" class=\"text\" name=\"pwd\" value=\"{PWD}\"/><p class=\"des\">Device Host Name</p><label for=\"device\">Device Name</label><input type=\"text\" class=\"text\" name=\"device\" value=\"{DEVICE}\"/><a class=\"erase\" href=\"/erase\">ERASE SETTINGS (not WiFi)</a><p class=\"des\">Inverter</p>{INVERTERS}<br/><p class=\"subdes\">General</p><label for=\"invInterval\">Interval (s)</label><input type=\"text\" class=\"text\" name=\"invInterval\" value=\"{INV_INTVL}\"/><p class=\"des\">Pinout (Wemos)</p>{PINOUT}<p class=\"des\">Radio (NRF24L01+)</p><label for=\"rf24Power\">Amplifier Power Level</label><select name=\"rf24Power\">{RF24}</select><p class=\"des\">MQTT</p><label for=\"mqttAddr\">Broker / Server IP</label><input type=\"text\" class=\"text\" name=\"mqttAddr\" value=\"{MQTT_ADDR}\"/><label for=\"mqttPort\">Port</label><input type=\"text\" class=\"text\" name=\"mqttPort\" value=\"{MQTT_PORT}\"/><label for=\"mqttUser\">Username (optional)</label><input type=\"text\" class=\"text\" name=\"mqttUser\" value=\"{MQTT_USER}\"/><label for=\"mqttPwd\">Password (optional)</label><input type=\"text\" class=\"text\" name=\"mqttPwd\" value=\"{MQTT_PWD}\"/><label for=\"mqttTopic\">Topic</label><input type=\"text\" class=\"text\" name=\"mqttTopic\" value=\"{MQTT_TOPIC}\"/><label for=\"mqttIntvl\">Interval (s)</label><input type=\"text\" class=\"text\" name=\"mqttIntvl\" value=\"{MQTT_INTVL}\"/><p class=\"des\">Serial Console</p><label for=\"serEn\">print inverter data</label><input type=\"checkbox\" class=\"cb\" name=\"serEn\" {SER_VAL_CB}/><br/><label for=\"serDbg\">print RF24 debug</label><input type=\"checkbox\" class=\"cb\" name=\"serDbg\" {SER_DBG_CB}/><br/><label for=\"serIntvl\">Interval (s)</label><input type=\"text\" class=\"text\" name=\"serIntvl\" value=\"{SER_INTVL}\"/><p class=\"des\"> </p><label for=\"reboot\">Reboot device after successful save</label><input type=\"checkbox\" class=\"cb\" name=\"reboot\"/><input type=\"submit\" value=\"save\" class=\"btn\" /></form></div></div><div id=\"footer\"><p class=\"left\"><a href=\"{IP}/\">Home</a></p><p class=\"left\"><a href=\"{IP}/update\">Update Firmware</a></p><p class=\"right\">AHOY - {VERSION}</p><p class=\"right\"><a href=\"{IP}/factory\">Factory Reset</a></p><p class=\"right\"><a href=\"{IP}/reboot\">Reboot</a></p></div></body></html>";
|
const char setup_html[] PROGMEM = "<!doctype html><html><head><title>Setup - {DEVICE}</title><link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\"/><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"></head><body><h1>Setup</h1><div id=\"setup\" class=\"content\"><div id=\"content\"><p>Enter the credentials to your prefered WiFi station. After rebooting the device tries to connect with this information. </p><form method=\"post\" action=\"{IP}/save\"><p class=\"des\">WiFi</p><label for=\"ssid\">SSID</label><input type=\"text\" class=\"text\" name=\"ssid\" value=\"{SSID}\"/><label for=\"pwd\">Password</label><input type=\"password\" class=\"text\" name=\"pwd\" value=\"{PWD}\"/><p class=\"des\">Device Host Name</p><label for=\"device\">Device Name</label><input type=\"text\" class=\"text\" name=\"device\" value=\"{DEVICE}\"/><a class=\"erase\" href=\"/erase\">ERASE SETTINGS (not WiFi)</a><p class=\"des\">Inverter</p>{INVERTERS}<br/><p class=\"subdes\">General</p><label for=\"invInterval\">Interval (s)</label><input type=\"text\" class=\"text\" name=\"invInterval\" value=\"{INV_INTVL}\"/><p class=\"des\">Pinout (Wemos)</p>{PINOUT}<p class=\"des\">Radio (NRF24L01+)</p><label for=\"rf24Power\">Amplifier Power Level</label><select name=\"rf24Power\">{RF24}</select><p class=\"des\">MQTT</p><label for=\"mqttAddr\">Broker / Server IP</label><input type=\"text\" class=\"text\" name=\"mqttAddr\" value=\"{MQTT_ADDR}\"/><label for=\"mqttPort\">Port</label><input type=\"text\" class=\"text\" name=\"mqttPort\" value=\"{MQTT_PORT}\"/><label for=\"mqttUser\">Username (optional)</label><input type=\"text\" class=\"text\" name=\"mqttUser\" value=\"{MQTT_USER}\"/><label for=\"mqttPwd\">Password (optional)</label><input type=\"text\" class=\"text\" name=\"mqttPwd\" value=\"{MQTT_PWD}\"/><label for=\"mqttTopic\">Topic</label><input type=\"text\" class=\"text\" name=\"mqttTopic\" value=\"{MQTT_TOPIC}\"/><label for=\"mqttIntvl\">Interval (s)</label><input type=\"text\" class=\"text\" name=\"mqttIntvl\" value=\"{MQTT_INTVL}\"/><p class=\"des\">Serial Console</p><label for=\"serEn\">print inverter data</label><input type=\"checkbox\" class=\"cb\" name=\"serEn\" {SER_VAL_CB}/><br/><label for=\"serDbg\">print RF24 debug</label><input type=\"checkbox\" class=\"cb\" name=\"serDbg\" {SER_DBG_CB}/><br/><label for=\"serIntvl\">Interval (s)</label><input type=\"text\" class=\"text\" name=\"serIntvl\" value=\"{SER_INTVL}\"/><p class=\"des\"> </p><label for=\"reboot\">Reboot device after successful save</label><input type=\"checkbox\" class=\"cb\" name=\"reboot\"/><input type=\"submit\" value=\"save\" class=\"btn\" /></form></div></div><div id=\"footer\"><p class=\"left\"><a href=\"{IP}/\">Home</a></p><p class=\"left\"><a href=\"{IP}/update\">Update Firmware</a></p><p class=\"right\">AHOY - {VERSION}</p><p class=\"right\"><a href=\"{IP}/factory\">Factory Reset</a></p><p class=\"right\"><a href=\"{IP}/reboot\">Reboot</a></p></div></body></html>";
|
||||||
#endif /*__SETUP_H__*/
|
#endif /*__SETUP_HTML_H__*/
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#ifndef __STYLE_H__
|
#ifndef __STYLE_CSS_H__
|
||||||
#define __STYLE_H__
|
#define __STYLE_CSS_H__
|
||||||
const char style_css[] PROGMEM = "h1 {margin:0;padding:20pt;font-size:22pt;color:#fff;background-color:#006ec0;display:block;text-transform:uppercase;}html, body {font-family:Arial;margin:0;padding:0;}p {text-align:justify;font-size:13pt;}.des {margin-top:35px;font-size:13pt;color:#006ec0;}.subdes {font-size:12pt;color:#006ec0;margin-left:7px;}a:link, a:visited {text-decoration:none;font-size:13pt;color:#006ec0;}a:hover, a:focus {color:#f00;}a.erase {background-color:#006ec0;color:#fff;padding:7px;display:inline-block;margin-top:30px;float:right;}#content {padding:15px 15px 60px 15px;}#footer {position:fixed;bottom:0px;height:45px;background-color:#006ec0;width:100%;border-top:5px solid #fff;}#footer p, #footer a {color:#fff;padding:0 7px 0 7px;font-size:10pt !important;}div.content {background-color:#fff;padding-bottom:65px;overflow:auto;}input, select {padding:7px;font-size:13pt;}input.text, select {width:70%;box-sizing:border-box;margin-bottom:10px;border:1px solid #ccc;}input.btn {background-color:#006ec0;color:#fff;border:0px;float:right;margin:10px 0 30px;text-transform:uppercase;}input.cb {margin-bottom:20px;}label {width:20%;display:inline-block;font-size:12pt;padding-right:10px;margin-left:10px;}.left {float:left;}.right {float:right;}div.ch-iv {width:100%;background-color:#32b004;display:inline-block;margin-bottom:20px;padding-bottom:20px;overflow:auto;}div.ch {width:250px;min-height:420px;background-color:#006ec0;display:inline-block;margin-right:20px;margin-bottom:20px;overflow:auto;padding-bottom:20px;}div.ch .value, div.ch .info, div.ch .head, div.ch-iv .value, div.ch-iv .info, div.ch-iv .head {color:#fff;display:block;width:100%;text-align:center;}.subgrp {float:left;width:250px;}div.ch .unit, div.ch-iv .unit {font-size:19px;margin-left:10px;}div.ch .value, div.ch-iv .value {margin-top:20px;font-size:30px;}div.ch .info, div.ch-iv .info {margin-top:3px;font-size:10px;}div.ch .head {background-color:#003c80;padding:10px 0 10px 0;}div.ch-iv .head {background-color:#1c6800;padding:10px 0 10px 0;}div.iv {max-width:1060px;}div.ch:last-child {margin-right:0px !important;}#note {margin:50px 10px 10px 10px;padding-top:10px;width:100%;border-top:1px solid #bbb;}";
|
const char style_css[] PROGMEM = "h1 {margin:0;padding:20pt;font-size:22pt;color:#fff;background-color:#006ec0;display:block;text-transform:uppercase;}html, body {font-family:Arial;margin:0;padding:0;}p {text-align:justify;font-size:13pt;}.des {margin-top:35px;font-size:13pt;color:#006ec0;}.subdes {font-size:12pt;color:#006ec0;margin-left:7px;}a:link, a:visited {text-decoration:none;font-size:13pt;color:#006ec0;}a:hover, a:focus {color:#f00;}a.erase {background-color:#006ec0;color:#fff;padding:7px;display:inline-block;margin-top:30px;float:right;}#content {padding:15px 15px 60px 15px;}#footer {position:fixed;bottom:0px;height:45px;background-color:#006ec0;width:100%;border-top:5px solid #fff;}#footer p, #footer a {color:#fff;padding:0 7px 0 7px;font-size:10pt !important;}div.content {background-color:#fff;padding-bottom:65px;overflow:auto;}input, select {padding:7px;font-size:13pt;}input.text, select {width:70%;box-sizing:border-box;margin-bottom:10px;border:1px solid #ccc;}input.btn {background-color:#006ec0;color:#fff;border:0px;float:right;margin:10px 0 30px;text-transform:uppercase;}input.cb {margin-bottom:20px;}label {width:20%;display:inline-block;font-size:12pt;padding-right:10px;margin-left:10px;}.left {float:left;}.right {float:right;}div.ch-iv {width:100%;background-color:#32b004;display:inline-block;margin-bottom:20px;padding-bottom:20px;overflow:auto;}div.ch {width:250px;min-height:420px;background-color:#006ec0;display:inline-block;margin-right:20px;margin-bottom:20px;overflow:auto;padding-bottom:20px;}div.ch .value, div.ch .info, div.ch .head, div.ch-iv .value, div.ch-iv .info, div.ch-iv .head {color:#fff;display:block;width:100%;text-align:center;}.subgrp {float:left;width:250px;}div.ch .unit, div.ch-iv .unit {font-size:19px;margin-left:10px;}div.ch .value, div.ch-iv .value {margin-top:20px;font-size:30px;}div.ch .info, div.ch-iv .info {margin-top:3px;font-size:10px;}div.ch .head {background-color:#003c80;padding:10px 0 10px 0;}div.ch-iv .head {background-color:#1c6800;padding:10px 0 10px 0;}div.iv {max-width:1060px;}div.ch:last-child {margin-right:0px !important;}#note {margin:50px 10px 10px 10px;padding-top:10px;width:100%;border-top:1px solid #bbb;}";
|
||||||
#endif /*__STYLE_H__*/
|
#endif /*__STYLE_CSS_H__*/
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue