knx/examples/knx-433Dio/knx-433Dio.ino
zelogik 21a05ae9b3
Add knx-433 (#122)
* knx-pzem004v30

Add first draft of a pzem-004t power/current/tension/etc.. on your main line (BE CAREFUL WITH VOLTAGE!)

PZEM-004t-v30 wired on a samd21 with the use of Sercom2

Use with slight modification of: https://github.com/mandulaj/PZEM-004T-v30
View issue:  https://github.com/mandulaj/PZEM-004T-v30/issues/43

* Rename examples/knx-pzem0004t.xml to examples/knx-pzem004/knx-pzem0004t.xml

* Delete knx-pzem004t.knxprod

* Delete pzem-004t-v30.ino

* Update: 'just move to right directory'

* Update knx-pzem0004t.xml

* Add: ProgMode

* Fix/Update/Add

Add: ResetEnergy function with datetime
Update: led Class
Fix: many typo, errors

* Cleaning

Some strange bug/feature...
Information is transmitted only when the device got time from KNX, I have put 
        if (timeStatus() == timeSet && resetPeriod != 0)
        {
           resetEnergyLoop();
        }

But don't know if it's enough...

* Create knx-433Dio.ino

* Add Files:

README.md

.xml and knxprod files

* Delete pzem-004t-v30.ino

* Update pzem-004t-v30.ino
2021-02-09 02:37:14 +01:00

369 lines
10 KiB
C++

#include <knx.h>
//#include <DiOremote.h>
//#define DEBUGSERIAL 1
#ifdef DEBUGSERIAL
#define DPRINT(...) SerialUSB.print(__VA_ARGS__)
#define DPRINTLN(...) SerialUSB.println(__VA_ARGS__)
#include <MemoryFree.h>
#include <pgmStrToRAM.h>
#else
#define DPRINT(...) //now defines a blank line
#define DPRINTLN(...) //now defines a blank line
#endif
#define goButton1 knx.getGroupObject(1)
#define goButton2 knx.getGroupObject(2)
#define goButton3 knx.getGroupObject(3)
#define goButtonAll knx.getGroupObject(4)
#define goProgMode knx.getGroupObject(5)
//DiOremote myRemote = DiOremote(6);
//void function2();
//void function1(void (*)());
//void loop() {
// function1(function2);
//}
//Global Const
const uint8_t ets_startupTimeout[7] = {0, 1, 2, 3, 4, 5, 6};
const uint16_t ets_timePeriod[7] = {0, 1, 5, 15, 1 * 60, 5 * 60, 15 * 60};
const uint8_t ets_progMode[7] = {0, 1, 2 * 60, 3 * 60, 4 * 60, 5 * 60, 10 * 60}; //need knxprod update... ?
const uint8_t ledPin = LED_BUILTIN;
const uint8_t rfPin = 6;
// //Protocol timing (in us)
// #define DiOremote_START_FRAME_1 220
// #define DiOremote_START_FRAME_0 2675
// #define DiOremote_THIGH 220
// #define DiOremote_TLOW_0 350 short
// #define DiOremote_TLOW_1 1400 long
// #define DiOremote_END_FRAME_1 220
// #define DiOremote_END_FRAME_0 10600
// Global Variable
bool progMode = true;
// bool codeSendindBlock = false;
uint8_t percentCycle = 0; // better to define a global or read knx.paramByte each time... ?
uint32_t timePeriod = 0; // same here,
uint32_t timerProgMode = 0; // same here,
uint32_t ch1_on, ch1_off, ch2_on, ch2_off, ch3_on, ch3_off, chall_on, chall_off;
class RfCode {
private:
uint8_t _rfPin;
uint32_t _codeValueOn;
uint32_t _codeValueOff;
uint8_t _GOaddress;
const uint16_t THIGH = 220, TSTART = 2675, TSHORT = 220, TLONG = 1400, TEND = 10600;
uint8_t _loopCount = 0; // fixed ==5
bool lastState = false;
uint32_t _codePending = 0;
uint32_t _codePendingMemory = _codePending;
uint8_t _loopPending = 0; // fixed ==32
bool _sendMsgPending= false;
enum PulseStates {
PULSE_INIT,
PULSE_KEY1, //32 times loop
PULSE_KEY2, //32 times loop
PULSE_END
};
PulseStates pulseStates = PULSE_INIT;
bool pulseSend(const uint16_t delayHigh, const uint16_t delayLow){ //alike state machine?
static bool initPulse = false;
static bool highDone = false;
static uint32_t pulseLastTime = 0;
uint32_t currentTime = micros();
if (!initPulse){
initPulse = true;
digitalWrite(_rfPin, HIGH);
pulseLastTime = currentTime;
}
else if (currentTime - pulseLastTime >= delayHigh && !highDone)
{
digitalWrite(_rfPin, LOW);
pulseLastTime = currentTime;
highDone = true;
}
else if (currentTime - pulseLastTime >= delayLow && highDone)
{
initPulse = false;
highDone = false;
}
return !initPulse;
}
uint16_t TTime(bool invert){
uint16_t TTIME;
if (_codePending & 0x80000000L)// future bug if uint32_t _codePengin > 2^32 / 2 ?
{
TTIME = invert ? TSHORT : TLONG;
}
else
{
TTIME = invert ? TLONG : TSHORT;
}
return TTIME;
}
public:
RfCode(uint8_t rfPin){
_rfPin = rfPin;
pinMode(_rfPin, OUTPUT);
}
// void init(uint8_t addr, uint32_t codeValueOn, uint32_t codeValueOff){ //GroupObject &device, long timeOn){
// _codeValueOn = codeValueOn;
// _codeValueOff = codeValueOff;
// _GOaddress = addr;
// }
void setState(bool modeOnOff, uint32_t codeValueOn, uint32_t codeValueOff){
if (!_sendMsgPending)
{
_sendMsgPending = true;
_codeValueOn = codeValueOn;
_codeValueOff = codeValueOff;
// _GOaddress = addr;
if (modeOnOff){
_codePending = _codeValueOn;
// SerialUSB.println(_codePending);
}
else
{
_codePending = _codeValueOff;
// SerialUSB.println(_codePending);
}
_codePendingMemory = _codePending;
}
}
// bool getMsgPendingState(){
// return _sendMsgPending;
// }
void loop(){
if (_sendMsgPending)
{
// needed to block setState of another Class, yes FIFO is better...
// codeSendindBlock = true;
if (_loopCount < 5)
{
switch (pulseStates){
case PULSE_INIT:
if (pulseSend(THIGH, TSTART)){
pulseStates = PULSE_KEY1;
}
break;
case PULSE_KEY1:
if (pulseSend(THIGH, TTime(false)))
{
pulseStates = PULSE_KEY2;
}
break;
case PULSE_KEY2:
if (pulseSend(THIGH, TTime(true)))
{
if (_loopPending < 32){
_codePending <<= 1;
_loopPending++;
pulseStates = PULSE_KEY1; // next loop !
}
else{ // finish!
pulseStates = PULSE_END;
}
}
break;
case PULSE_END:
if (pulseSend(THIGH, TEND)){
_loopCount++;
_codePending = _codePendingMemory;
_loopPending = 0;
pulseStates = PULSE_INIT;
}
break;
default:
break;
}
}
else
{
_loopCount = 0;
_sendMsgPending = false;
// codeSendindBlock = false;
}
}
}
};
class Blinker
{
private:
uint8_t ledPin_; // the number of the LED pin
uint32_t OnTime = 1000; // milliseconds of on-time
uint32_t OffTime = 1000; // milliseconds of off-time
bool ledState = LOW; // ledState used to set the LED
uint32_t previousMillis; // will store last time LED was updated
void setOutput(bool state_, uint32_t currentMillis_){
ledState = state_;
previousMillis = currentMillis_;
digitalWrite(ledPin_, state_);
}
public:
Blinker(uint8_t pin)
{
ledPin_ = pin;
pinMode(ledPin_, OUTPUT);
previousMillis = 0;
}
void set(uint32_t on, uint32_t off){
OnTime = on;
OffTime = off;
}
void loop(){
uint32_t currentMillis = millis();
if((ledState == HIGH) && (currentMillis - previousMillis >= OnTime))
{
setOutput(LOW, currentMillis);
}
else if ((ledState == LOW) && (currentMillis - previousMillis >= OffTime))
{
setOutput(HIGH, currentMillis);
}
}
};
RfCode button = RfCode(5);
Blinker led = Blinker(ledPin);
void callBackButton1(GroupObject& go){
button.setState((bool)go.value(), ch1_on, ch1_off);
}
void callBackButton2(GroupObject& go){
button.setState((bool)go.value(), ch2_on, ch2_off);
}
void callBackButton3(GroupObject& go){
button.setState((bool)go.value(), ch3_on, ch3_off);
}
void callBackButtonAll(GroupObject& go){
button.setState((bool)go.value(), chall_on, ch3_off);
}
void callBackProgMode(GroupObject& go){
progMode = (bool)go.value();
}
void setup() {
// #ifdef DEBUGSERIAL
// SerialUSB.begin(9600);
// while (!SerialUSB) { //wait for DEBUGING
// ; // wait for serial port to connect. Needed for native USB port only
// }
// ArduinoPlatform::SerialDebug = &SerialUSB;
// #endif
randomSeed(millis());
// knx.bau().deviceObject().individualAddress(1);
knx.readMemory();
if (knx.configured())
{
DPRINT("Setup: KNX Configuration...");
progMode = false; // don't need to put device in progMode.
int confStartupTime = ets_startupTimeout[knx.paramByte(0)] * 1000;
delay(confStartupTime); // the only delay used, why make a withoutDelay function for that?
timePeriod = ets_timePeriod[knx.paramByte(1)] * 1000;
// timerProgMode = ets_progMode[knx.paramByte(34)] * 1000;
ch1_on = knx.paramInt(2);
ch1_off = knx.paramInt(6);
goButton1.callback(callBackButton1);
goButton1.dataPointType(DPT_Switch);
ch2_on = knx.paramInt(10);
ch2_off = knx.paramInt(14);
goButton2.callback(callBackButton2);
goButton2.dataPointType(DPT_Switch);
ch3_on = knx.paramInt(18);
ch3_off = knx.paramInt(22);
goButton3.callback(callBackButton3);
goButton3.dataPointType(DPT_Switch);
chall_on = knx.paramByte(26);
chall_off = knx.paramByte(30);
goButtonAll.callback(callBackButtonAll);
goButtonAll.dataPointType(DPT_Switch);
goProgMode.callback(callBackProgMode);
goProgMode.dataPointType(DPT_Trigger);
DPRINTLN("Finished");
}
knx.ledPin(5);
knx.ledPinActiveOn(HIGH);
knx.buttonPin(9);
knx.start();
led.set(2000, 2000);
}
void loop()
{
knx.loop();
led.loop();
if (knx.configured() && !progMode)
{
button.loop();
}
else if (progMode)
{
prodModeLoop();
}
}
void prodModeLoop(){ // run Only if progMode triggered ( at start or callback)
const uint32_t timerProgMode = ( 15 * 60 * 1000 ) ; // 15min
static uint32_t timerProgPrevMillis = 0;
if (!knx.progMode())
{
knx.progMode(true);
led.set(500, 500);
timerProgPrevMillis = millis();
DPRINTLN("progModeLoop Start");
}
else
{
if (millis() - timerProgPrevMillis > timerProgMode) {
knx.progMode(false);
goProgMode.value(false);
progMode = 0;
led.set(100, 100); // panic!
DPRINTLN("progModeLoop Stop");
}
}
}