diff --git a/examples/knx-433Dio/KNXto433.xml b/examples/knx-433Dio/KNXto433.xml
new file mode 100644
index 0000000..888c1e9
--- /dev/null
+++ b/examples/knx-433Dio/KNXto433.xml
@@ -0,0 +1,153 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/knx-433Dio/README.md b/examples/knx-433Dio/README.md
new file mode 100644
index 0000000..31d7ce1
--- /dev/null
+++ b/examples/knx-433Dio/README.md
@@ -0,0 +1,32 @@
+Control Chacon/DIO 433Mhz plug like that: (not an affiliated link just for info)
+https://www.amazon.fr/DiO-Connected-Home-t%C3%A9l%C3%A9command%C3%A9es-t%C3%A9l%C3%A9commande/dp/B005LKMAW0
+
+
+Hardware:
+- Samd21 (gy-samd21)
+- FS 1000A (cheap 433 transmitter)
+- TpUart KNX
+- logic level converter
+- Chacon/DIO 433Mhz plug (must work with every dumb 433mhz plug/remote that support the HomeEasy protocol)
+
+Software
+- change the rfPin variable, compile and tranfert into the samd21 (or any microcontroller)
+- (maybe) adapt THIGH and TLOW in rfCode class for your case.
+
+Before configuring ETS, you need to receive the 433mhz code for each button of your remote.
+Take an arduino UNO, plug the FS1000a receiver, look on github/google to receive the code rc-switch or https://charleslabs.fr/fr/project-Contr%C3%B4le+de+prises+DiO+avec+Arduino (in french), or https://caron.ws/diy-cartes-microcontroleurs/piloter-vos-prises-chacon-rf433mhz-arduino/ ( in french too)
+
+
+for me it's : 1806947472 and 1806947456 for the channel 1 on/off, etc...
+
+Now in ETS put the received 433Mhz code into parameters.
+-> Full Download in ETS and enjoy.
+
+
+
+Feature:
+This code is delay() free, blocking code free (ie: no long while or for loop), to call the knx.loop() as fast as possible.
+
+
+
+
diff --git a/examples/knx-433Dio/knx-433.knxprod b/examples/knx-433Dio/knx-433.knxprod
new file mode 100644
index 0000000..b3d72fc
Binary files /dev/null and b/examples/knx-433Dio/knx-433.knxprod differ
diff --git a/examples/knx-433Dio/knx-433Dio.ino b/examples/knx-433Dio/knx-433Dio.ino
new file mode 100644
index 0000000..841dd6a
--- /dev/null
+++ b/examples/knx-433Dio/knx-433Dio.ino
@@ -0,0 +1,368 @@
+#include
+//#include
+
+//#define DEBUGSERIAL 1
+#ifdef DEBUGSERIAL
+ #define DPRINT(...) SerialUSB.print(__VA_ARGS__)
+ #define DPRINTLN(...) SerialUSB.println(__VA_ARGS__)
+ #include
+ #include
+#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");
+ }
+ }
+}
diff --git a/examples/knx-pzem004/pzem-004t-v30.ino b/examples/knx-pzem004/pzem-004t-v30.ino
index 2bc92ff..2bf6527 100644
--- a/examples/knx-pzem004/pzem-004t-v30.ino
+++ b/examples/knx-pzem004/pzem-004t-v30.ino
@@ -38,7 +38,7 @@ const uint8_t physicalCount = 6; // voltage,current,power_factor,power,energy,fr
uint8_t percentCycle = 0; // better to define a global or read knx.paramByte each time... ?
uint32_t timePeriod = 0; // same here,
uint8_t resetPeriod = 0; //same here ...
-uint8_t resetEnergy = 0; // and here... disabled/day/week/month
+//uint8_t resetEnergy = 0; // and here... disabled/day/week/month
bool progMode = true;
@@ -54,11 +54,10 @@ struct Physical {
void loop(){
// unsigned long currentMillis = millis();
// Delta Change update as defined in ETS
- int32_t deltaPercent = ( 100 * ( _value - _lastValue ) / _value );
+ float deltaPercent = ( 100 * ( _value - _lastValue ) / _value );
if ( percentCycle != 0 && abs(deltaPercent) >= percentCycle )
{
_trigger = true;
- _lastValue = _value;
}
// Refresh groupAddress value as defined in ETS since last update
@@ -70,6 +69,7 @@ struct Physical {
// UpdateGO but send to bus only if triggered by time or value change percentage
if (_trigger){
knx.getGroupObject(_GOaddr).value(_value, _dpt);
+ _lastValue = _value;
_lastMillis = millis();
_trigger = false;
}else{
@@ -143,7 +143,6 @@ class Blinker
Blinker led = Blinker(ledPin);
-
void callBackProgMode(GroupObject& go){
progMode = (bool)go.value();
}
@@ -172,7 +171,7 @@ void resetCallback(GroupObject& go)
{
if (go.value())
{
- resetEnergy = true;
+ pzem.resetEnergy();
goReset.value(false);
}
}
@@ -181,7 +180,7 @@ void setup() {
pinPeripheral(PIN_SERIAL2_RX, PIO_SERCOM);
pinPeripheral(PIN_SERIAL2_TX, PIO_SERCOM);
- SerialUSB.begin(9600);
+// SerialUSB.begin(9600);
Serial2.begin(9600);
ArduinoPlatform::SerialDebug = &SerialUSB;
@@ -238,12 +237,17 @@ void loop() {
if (knx.configured() && !progMode)
{
refreshValueLoop();
- resetEnergyLoop();
for (uint8_t i=0; i< physicalCount; i++)
{
Physical[i].loop();
}
+
+ if (timeStatus() == timeSet && resetPeriod != 0)
+ {
+ resetEnergyLoop();
+ }
+
}
else if (progMode)
{
@@ -257,7 +261,7 @@ void refreshValueLoop(){
if (millis() - lastPzemUpdate >= pzemInterval)
{
- for (uint8_t i=0; i< physicalCount; i++)
+ for (uint8_t i=0; i < physicalCount; i++)
{
float isaValue;
switch (i) { //maybe a pointer or reference could be nicer...
@@ -282,11 +286,18 @@ void refreshValueLoop(){
default:
break;
}
+
if(!isnan(isaValue))
{
Physical[i].setValue(isaValue);
}
+ else
+ {
+ Physical[i].setValue(-1);
+ }
}
+ lastPzemUpdate = millis();
+ led.set(500, 1000);
}
}
@@ -339,14 +350,14 @@ void prodModeLoop(){ // run Only if progMode triggered ( at start or callback)
{
knx.progMode(true);
timerProgPrevMillis = millis();
- led.set(500, 250);
+ led.set(50, 100);
}
else
{
if (millis() - timerProgPrevMillis > timerProgMode) {
knx.progMode(false);
goProgMode.value(false);
- progMode = 0;
+ progMode = false;
}
}
}