├── HBW-1W-T10 ├── HBW-1W-T10.ino ├── HBW-1W-T10_config_example.h ├── hbw_1w_t10_v1.xml └── readme.txt ├── HBW-CC-DT3-T6 ├── HBW-CC-DT3-T6.ino ├── HBW-CC-DT3-T6_config_example.h ├── HBWDeltaT.cpp ├── HBWDeltaT.h ├── HBWLinkKeyInfoEventSensor.cpp ├── HBWLinkKeyInfoEventSensor.h ├── HBWLinkKeyInfoEventSensor.hpp ├── hbw_cc_dt3_t6.xml └── readme.txt ├── HBW-CC-VD-8 ├── HBW-CC-VD-8.ino ├── HBW-CC-VD-8_config_example.h ├── hbw_cc_vd2.xml ├── hbw_cc_vd8.xml └── readme.txt ├── HBW-CC-WW-SPktS ├── HBW-CC-WW-SPktS.ino ├── HBW-CC-WW-SPktS_config_example.h ├── HBWDeltaT.cpp ├── HBWDeltaT.h ├── HBWSPktS.cpp ├── HBWSPktS.h ├── hbw-cc-ww-spkts.xml └── readme.txt ├── HBW-DIS-Key-4 ├── HBW-DIS-Key-4.ino ├── HBW-DIS-Key-4_config_example.h ├── HBWDisplayLCD.cpp ├── HBWDisplayLCD.h ├── HBWLinkInfoKeyEventActuator.cpp ├── HBWLinkInfoKeyEventActuator.h ├── HBWLinkInfoKeyEventActuator.hpp ├── hbw-dis-key-4.xml └── readme.txt ├── HBW-LC-BL-4 ├── HBW-LC-BL-4.ino ├── HBW-LC-BL-4.ino.hex ├── HBW-LC-BL-4.ino.with_bootloader.hex ├── HBW-LC-BL-4_config_example.h ├── hbw_lc_bl-4.xml └── readme.txt ├── HBW-LC-BL-8 ├── HBW-LC-BL-8.ino ├── HBW-LC-BL-8_config_example.h ├── hbw_lc_bl-8.xml └── readme.txt ├── HBW-LC-Sw-12 ├── HBW-LC-Sw-12.ino ├── HBW-LC-Sw-12.xml ├── HBW-LC-Sw-12_config_example.h ├── HBWAnalogPow.cpp ├── HBWAnalogPow.h ├── HBWSwitchSerialAdvanced.cpp ├── HBWSwitchSerialAdvanced.h ├── ShiftRegister74HC595.cpp ├── ShiftRegister74HC595.h ├── ShiftRegister74HC595.hpp └── readme.txt ├── HBW-LC-Sw-8 ├── HBW-LC-Sw-8.ino ├── HBW-LC-Sw-8.ino.eightanaloginputs.hex ├── HBW-LC-Sw-8.ino.with_bootloader.eightanaloginputs.hex ├── HBW-LC-Sw-8.xml ├── HBW-LC-Sw-8_config_example.h └── readme.txt ├── HBW-LC-Sw-8_AdvancedPeering ├── HBW-LC-Sw-8.xml ├── HBW-LC-Sw-8_AdvancedPeering.ino ├── HBW-LC-Sw-8_AdvancedPeering_config_example.h └── readme.txt ├── HBW-SC-10-Dim-6 ├── HBW-SC-10-Dim-6.ino ├── HBW-SC-10-Dim-6_config_example.h ├── HBWDimmerVirtual.cpp ├── HBWDimmerVirtual.h ├── HBWKeyVirtual.cpp ├── HBWKeyVirtual.h ├── SetupTimer_328p.h ├── hbw_sc-10_dim-6.xml ├── hbw_sc-10_dim-6_v0.7.xml └── readme.txt ├── HBW-Sen-DB-4 ├── HBW-Sen-DB-4.ino ├── HBW-Sen-DB-4_config_example.h ├── HBWKeyDoorbell.cpp ├── HBWKeyDoorbell.h ├── hbw-sen-db-4.xml ├── hbw-sen-db-4_v0.2.xml ├── pitches.h └── readme.txt ├── HBW-Sen-EP ├── HBW-Sen-EP.ino ├── HBW-Sen-EP_config_example.h ├── hbw-sen-ep.xml └── readme.txt ├── HBW-Sen-EP_interrupt-based ├── HBW-Sen-EP_interrupt-based.ino ├── HBW-Sen-EP_interrupt-based_config_example.h ├── HBW-Sen-EP_interrupt.h ├── UC121902-TNARX-A.h ├── hbw-sen-ep.xml └── readme.txt ├── HBW-Sen-Key-12 ├── HBW-Sen-Key-12.ino ├── HBW-Sen-Key-12_config_example.h └── hbw_sen_key_12.xml ├── HBW-Sen-SC-12-DR ├── HBW-Sen-SC-12-DR.ino ├── HBW-Sen-SC-12-DR_config_example.h ├── hbw_sen_sc_12_dr.xml └── readme.txt ├── HBW-WDS-C7 ├── HBW-WDS-C7.ino ├── HBW-WDS-C7_latest.ino_50MHz.uf2 ├── HBWSIGNALDuino_adv.cpp ├── HBWSIGNALDuino_adv.h ├── HBWSIGNALDuino_adv │ ├── FastDelegate.h │ ├── SIGNALDuino.ino.hpp │ ├── SimpleFIFO.h │ ├── bitstore.h │ ├── cc1101.h │ ├── compile_config.h │ ├── output.h │ ├── signalDecoder.cpp │ ├── signalDecoder.h │ └── signalDecoder.hpp ├── HBWSIGNALDuino_bresser7in1.cpp ├── HBWSIGNALDuino_bresser7in1.h ├── bit_util.c ├── bit_util.h ├── bit_util.hpp ├── hbw_wds_c7.xml └── readme.txt ├── README.md ├── documentation ├── arduino_nano │ ├── mega328p_fuses-detailed_Engbedded.pdf │ ├── mega328p_fuses.txt │ └── mega328pb_fuses.txt └── quick-setup.txt └── libraries ├── ClickButton ├── Examples │ ├── LEDfader │ │ └── LEDfader.ino │ ├── MultiButtons │ │ └── MultiButtons.ino │ └── MultiClicks │ │ └── MultiClicks.ino └── keywords.txt ├── EEPROM24 ├── keywords.txt ├── library.properties └── src │ ├── EEPROM24.cpp │ └── EEPROM24.h ├── README.md ├── keywords.txt ├── library.properties └── src ├── ClickButton.cpp ├── ClickButton.h ├── FreeRam.cpp ├── FreeRam.h ├── HBWAnalogIn.cpp ├── HBWAnalogIn.h ├── HBWBlind.cpp ├── HBWBlind.h ├── HBWDimBacklight.cpp ├── HBWDimBacklight.h ├── HBWDimmerAdvanced.cpp ├── HBWDimmerAdvanced.h ├── HBWKey.cpp ├── HBWKey.h ├── HBWLinkBlindSimple.cpp ├── HBWLinkBlindSimple.h ├── HBWLinkBlindSimple.hpp ├── HBWLinkDimmerAdvanced.cpp ├── HBWLinkDimmerAdvanced.h ├── HBWLinkDimmerAdvanced.hpp ├── HBWLinkInfoEventActuator.cpp ├── HBWLinkInfoEventActuator.h ├── HBWLinkInfoEventActuator.hpp ├── HBWLinkInfoEventSensor.cpp ├── HBWLinkInfoEventSensor.h ├── HBWLinkInfoEventSensor.hpp ├── HBWLinkKey.cpp ├── HBWLinkKey.h ├── HBWLinkKey.hpp ├── HBWLinkSwitchAdvanced.cpp ├── HBWLinkSwitchAdvanced.h ├── HBWLinkSwitchAdvanced.hpp ├── HBWLinkSwitchSimple.cpp ├── HBWLinkSwitchSimple.h ├── HBWLinkSwitchSimple.hpp ├── HBWOneWireTempSensors.cpp ├── HBWOneWireTempSensors.h ├── HBWPids.cpp ├── HBWPids.h ├── HBWSenEP.cpp ├── HBWSenEP.h ├── HBWSenSC.cpp ├── HBWSenSC.h ├── HBWSoftwareSerial.cpp ├── HBWSoftwareSerial.h ├── HBWSwitch.cpp ├── HBWSwitch.h ├── HBWSwitchAdvanced.cpp ├── HBWSwitchAdvanced.h ├── HBWValve.cpp ├── HBWValve.h ├── HBW_eeprom.h ├── HBW_hardware.h ├── HBWired.cpp ├── HBWired.h └── HBWlibStateMachine.h /HBW-1W-T10/HBW-1W-T10_config_example.h: -------------------------------------------------------------------------------- 1 | /* Default / example configuation file. When using custom device config (pinout, EEPROM, etc.) or controller, 2 | * copy this file and adjust it. This would also avoid to owerwrite it with new versions from GitHub. */ 3 | 4 | // Arduino NANO / ATMega 328p config - RS485 bus is attached to SoftwareSerial by default, UART0 is used for serial debug. 5 | 6 | EEPROMClass* EepromPtr = &EEPROM; // use internal EEPROM 7 | 8 | // #define USE_HARDWARE_SERIAL // use hardware serial (USART) for final device - this disables debug output 9 | /* Undefine "HBW_DEBUG" in 'HBWired.h' to remove unneeded code. "HBW_DEBUG" also works as master switch, 10 | * as hbwdebug() or hbwdebughex() used in channels will point to empty functions. */ 11 | 12 | // Pins 13 | #ifdef USE_HARDWARE_SERIAL 14 | #define RS485_TXEN 2 // Transmit-Enable 15 | #define BUTTON A6 // Button fuer Factory-Reset etc. 16 | #define LED LED_BUILTIN // Signal-LED 17 | 18 | #define ONEWIRE_PIN 10 // Onewire Bus 19 | 20 | #else 21 | #define RS485_RXD 4 22 | #define RS485_TXD 2 23 | #define RS485_TXEN 3 // Transmit-Enable 24 | #define BUTTON 8 // Button fuer Factory-Reset etc. 25 | #define LED LED_BUILTIN // Signal-LED 26 | 27 | #define ONEWIRE_PIN 10 // Onewire Bus 28 | 29 | #include "FreeRam.h" 30 | #include 31 | HBWSoftwareSerial rs485(RS485_RXD, RS485_TXD); // RX, TX 32 | #endif //USE_HARDWARE_SERIAL 33 | 34 | -------------------------------------------------------------------------------- /HBW-1W-T10/readme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThorstenPferdekaemper/HBWired/27cbac299529a660c791c42f2cece74439513561/HBW-1W-T10/readme.txt -------------------------------------------------------------------------------- /HBW-CC-DT3-T6/HBW-CC-DT3-T6_config_example.h: -------------------------------------------------------------------------------- 1 | /* Default / example configuation file. When using custom device config (pinout, EEPROM, etc.) or controller, 2 | * copy this file and adjust it. This would also avoid to owerwrite it with new versions from GitHub. */ 3 | 4 | // Arduino NANO / ATMega 328p config - RS485 bus is attached to SoftwareSerial by default, UART0 is used for serial debug. 5 | 6 | EEPROMClass* EepromPtr = &EEPROM; // use internal EEPROM 7 | 8 | // #define USE_HARDWARE_SERIAL // use hardware serial (USART) for final device - this disables debug output 9 | /* Undefine "HBW_DEBUG" in 'HBWired.h' to remove unneeded code. "HBW_DEBUG" also works as master switch, 10 | * as hbwdebug() or hbwdebughex() used in channels will point to empty functions. */ 11 | 12 | #ifdef USE_HARDWARE_SERIAL 13 | #define RS485_TXEN 2 // Transmit-Enable 14 | #define BUTTON A6 // Button fuer Factory-Reset etc. 15 | #define ADC_BUS_VOLTAGE A7 // analog input to measure bus voltage (optional) 16 | 17 | #define ONEWIRE_PIN A3 // Onewire Bus 18 | #define RELAY_1 5 19 | #define RELAY_2 6 20 | #define RELAY_3 3 21 | 22 | #define LED LED_BUILTIN // Signal-LED 23 | // #define BLOCKED_TWI_SDA A4 // used by I²C - SDA 24 | // #define BLOCKED_TWI_SCL A5 // used by I²C - SCL 25 | 26 | #else 27 | #define RS485_RXD 4 28 | #define RS485_TXD 2 29 | #define RS485_TXEN 3 // Transmit-Enable 30 | #define BUTTON 8 // Button fuer Factory-Reset etc. 31 | #define ADC_BUS_VOLTAGE A7 // analog input to measure bus voltage (optional) 32 | 33 | #define ONEWIRE_PIN 10 // Onewire Bus 34 | #define RELAY_1 5 35 | #define RELAY_2 6 36 | #define RELAY_3 A2 37 | 38 | #define LED LED_BUILTIN // Signal-LED 39 | 40 | #include 41 | #include 42 | HBWSoftwareSerial rs485(RS485_RXD, RS485_TXD); // RX, TX 43 | 44 | #endif 45 | 46 | -------------------------------------------------------------------------------- /HBW-CC-DT3-T6/HBWLinkKeyInfoEventSensor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ** HBWLinkKeyInfoEventSensor 3 | ** 4 | ** Einfache direkte Verknuepfung (Peering), vom Sensor ausgehend 5 | ** Ein Link-Objekt steht immer fuer alle (direkt aufeinander folgenden) Verknuepfungen 6 | ** des entsprechenden Typs. 7 | ** 8 | */ 9 | 10 | 11 | #include "HBWLinkKeyInfoEventSensor.h" 12 | -------------------------------------------------------------------------------- /HBW-CC-DT3-T6/HBWLinkKeyInfoEventSensor.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** HBWLinkKeyInfoEventSensor 3 | ** 4 | ** Einfache direkte Verknuepfung (Peering), vom Sensor ausgehend 5 | ** Ein Link-Objekt steht immer fuer alle (direkt aufeinander folgenden) Verknuepfungen 6 | ** des entsprechenden Typs. 7 | ** 8 | */ 9 | 10 | // TODO: remove these files and add option to the lib, allowing to combine different LinkSender 11 | 12 | #ifndef HBWLinkKeyInfoEventSensor_h 13 | #define HBWLinkKeyInfoEventSensor_h 14 | 15 | #include "HBWired.h" 16 | 17 | 18 | template 19 | class HBWLinkKeyInfoEventSensor : public HBWLinkSender { 20 | public: 21 | HBWLinkKeyInfoEventSensor(); 22 | void sendInfoEvent(HBWDevice* device, uint8_t srcChan, uint8_t length, uint8_t const * const data); 23 | void sendKeyEvent(HBWDevice* device, uint8_t srcChan, uint8_t keyPressNum, boolean longPress); 24 | private: 25 | static const uint8_t EEPROM_SIZE = 6; // "address_step" in XML 26 | }; 27 | 28 | #include "HBWLinkKeyInfoEventSensor.hpp" 29 | #endif 30 | -------------------------------------------------------------------------------- /HBW-CC-DT3-T6/HBWLinkKeyInfoEventSensor.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | ** HBWLinkKeyInfoEventSensor 3 | ** 4 | ** Einfache direkte Verknuepfung (Peering), vom Sensor ausgehend 5 | ** Ein Link-Objekt steht immer fuer alle (direkt aufeinander folgenden) Verknuepfungen 6 | ** des entsprechenden Typs. 7 | ** 8 | */ 9 | 10 | 11 | #ifdef Support_HBWLink_InfoEvent 12 | template 13 | HBWLinkKeyInfoEventSensor::HBWLinkKeyInfoEventSensor() { 14 | } 15 | 16 | 17 | // TODO: Der Beginn aller Verknuepfungen ist gleich. Eigentlich koennte man 18 | // das meiste in einer gemeinsamen Basisklasse abhandeln 19 | template 20 | void HBWLinkKeyInfoEventSensor::sendInfoEvent(HBWDevice* device, uint8_t srcChan, 21 | uint8_t length, uint8_t const * const data) { 22 | uint8_t channelEEPROM; 23 | uint32_t addrEEPROM; 24 | // care for peerings 25 | for(int i = 0; i < numLinks; i++) { 26 | // get channel number 27 | device->readEEPROM(&channelEEPROM, eepromStart + EEPROM_SIZE * i, 1); 28 | // valid peering? 29 | // TODO: Really like that? This always goes through all possible peerings 30 | if(channelEEPROM == 0xFF) continue; 31 | // channel is key? 32 | if(channelEEPROM != srcChan) continue; 33 | // get address and channel of actuator 34 | device->readEEPROM(&addrEEPROM, eepromStart + EEPROM_SIZE * i + 1, 4, true); 35 | device->readEEPROM(&channelEEPROM, eepromStart + EEPROM_SIZE * i +5, 1); 36 | // own address? -> internal peering 37 | if(addrEEPROM == device->getOwnAddress()) { 38 | device->receiveInfoEvent(addrEEPROM, srcChan, channelEEPROM, length, data); 39 | }else{ 40 | // external peering 41 | // TODO: If bus busy, then try to repeat. ...aber zuerst feststellen, wie das die Original-Module machen (bzw. hier einfach so lassen) 42 | /* byte result = */ 43 | device->sendInfoEvent(srcChan, length, data, addrEEPROM, channelEEPROM, !NEED_IDLE_BUS, 1); // free/idle bus was checked before calling sendInfoEvent. Send peer message only once 44 | }; 45 | }; 46 | } 47 | 48 | template 49 | void HBWLinkKeyInfoEventSensor::sendKeyEvent(HBWDevice* device, uint8_t srcChan, 50 | uint8_t keyPressNum, boolean longPress) { 51 | uint8_t channelEEPROM; 52 | uint32_t addrEEPROM; 53 | // care for peerings 54 | for(int i = 0; i < numLinks; i++) { 55 | // get channel number 56 | device->readEEPROM(&channelEEPROM, eepromStart + EEPROM_SIZE * i, 1); 57 | // valid peering? 58 | // TODO: Really like that? This always goes through all possible peerings 59 | if(channelEEPROM == 0xFF) continue; 60 | // channel is key? 61 | if(channelEEPROM != srcChan) continue; 62 | // get address and channel of actuator 63 | device->readEEPROM(&addrEEPROM, eepromStart + EEPROM_SIZE * i + 1, 4, true); 64 | device->readEEPROM(&channelEEPROM, eepromStart + EEPROM_SIZE * i +5, 1); 65 | // own address? -> internal peering 66 | if(addrEEPROM == device->getOwnAddress()) { 67 | device->receiveKeyEvent(addrEEPROM, srcChan, channelEEPROM, keyPressNum, longPress); 68 | }else{ 69 | // external peering 70 | // TODO: If bus busy, then try to repeat. ...aber zuerst feststellen, wie das die Original-Module machen (bzw. hier einfach so lassen) 71 | /* byte result = */ 72 | device->sendKeyEvent(srcChan, keyPressNum, longPress, addrEEPROM, channelEEPROM, !NEED_IDLE_BUS, 1); // free/idle bus was checked before calling sendKeyEvent - by broadcast message. Send peer message only once 73 | }; 74 | }; 75 | } 76 | #endif 77 | -------------------------------------------------------------------------------- /HBW-CC-DT3-T6/readme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThorstenPferdekaemper/HBWired/27cbac299529a660c791c42f2cece74439513561/HBW-CC-DT3-T6/readme.txt -------------------------------------------------------------------------------- /HBW-CC-VD-8/HBW-CC-VD-8_config_example.h: -------------------------------------------------------------------------------- 1 | /* Default / example configuation file. When using custom device config (pinout, EEPROM, etc.) or controller, 2 | * copy this file and adjust it. This would also avoid to owerwrite it with new versions from GitHub. */ 3 | 4 | // Arduino NANO / ATMega 328p config - RS485 bus is attached to SoftwareSerial by default, UART0 is used for serial debug. 5 | 6 | EEPROMClass* EepromPtr = &EEPROM; // use internal EEPROM 7 | 8 | #define USE_HARDWARE_SERIAL // use hardware serial (USART) for final device - this disables debug output 9 | /* Undefine "HBW_DEBUG" in 'HBWired.h' to remove unneeded code. "HBW_DEBUG" also works as master switch, 10 | * as hbwdebug() or hbwdebughex() used in channels will point to empty functions. */ 11 | 12 | // Pins 13 | #ifdef USE_HARDWARE_SERIAL 14 | #define RS485_TXEN 2 // Transmit-Enable 15 | #define BUTTON A6 // Button fuer Factory-Reset etc. 16 | #define LED LED_BUILTIN // Signal-LED 17 | #define ADC_BUS_VOLTAGE A7 // analog input to measure bus voltage 18 | 19 | #define ONEWIRE_PIN A5 // Onewire Bus 20 | #define VD1 A4 21 | #define VD2 8 22 | #define VD3 7 23 | #define VD4 4 24 | #define VD5 A0 25 | #define VD6 A1 26 | #define VD7 A2 27 | #define VD8 A3 28 | 29 | #else 30 | #define RS485_RXD 4 31 | #define RS485_TXD 2 32 | #define RS485_TXEN 3 // Transmit-Enable 33 | #define BUTTON 8 // Button fuer Factory-Reset etc. 34 | #define LED LED_BUILTIN // Signal-LED 35 | #define ADC_BUS_VOLTAGE A7 // analog input to measure bus voltage 36 | 37 | #define ONEWIRE_PIN 10 // Onewire Bus 38 | #define VD1 A1 39 | #define VD2 A2 40 | #define VD3 5 41 | #define VD4 6 42 | #define VD5 7 43 | #define VD6 12 44 | #define VD7 9 45 | #define VD8 A5 46 | 47 | #include "FreeRam.h" 48 | #include 49 | HBWSoftwareSerial rs485(RS485_RXD, RS485_TXD); // RX, TX 50 | #endif //USE_HARDWARE_SERIAL 51 | 52 | -------------------------------------------------------------------------------- /HBW-CC-VD-8/readme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThorstenPferdekaemper/HBWired/27cbac299529a660c791c42f2cece74439513561/HBW-CC-VD-8/readme.txt -------------------------------------------------------------------------------- /HBW-CC-WW-SPktS/HBW-CC-WW-SPktS_config_example.h: -------------------------------------------------------------------------------- 1 | /* Default / example configuation file. When using custom device config (pinout, EEPROM, etc.) or controller, 2 | * copy this file and adjust it. This would also avoid to owerwrite it with new versions from GitHub. */ 3 | 4 | // Arduino NANO / ATMega 328p config - RS485 bus is attached to SoftwareSerial by default, UART0 is used for serial debug. 5 | 6 | EEPROMClass* EepromPtr = &EEPROM; // use internal EEPROM 7 | 8 | // #define USE_HARDWARE_SERIAL // use hardware serial (USART) for final device - this disables debug output 9 | /* Undefine "HBW_DEBUG" in 'HBWired.h' to remove unneeded code. "HBW_DEBUG" also works as master switch, 10 | * as hbwdebug() or hbwdebughex() used in channels will point to empty functions. */ 11 | 12 | // Pins 13 | #define LED LED_BUILTIN // Signal-LED 14 | 15 | #ifdef USE_HARDWARE_SERIAL 16 | #define RS485_TXEN 2 // Transmit-Enable 17 | #define BUTTON A6 // Button fuer Factory-Reset etc. 18 | 19 | #define ONEWIRE_PIN A3 // Onewire Bus 20 | 21 | #define HEATER_PIN 3 // Schwingungspaketsteuerung Ausgang (controlled by timer1) 22 | 23 | #define RELAY_1 7 24 | #define RELAY_2 6 25 | 26 | // #define BLOCKED_TWI_SDA A4 // used by I²C - SDA 27 | // #define BLOCKED_TWI_SCL A5 // used by I²C - SCL 28 | 29 | #else 30 | #define RS485_RXD 4 31 | #define RS485_TXD 2 32 | #define RS485_TXEN 3 // Transmit-Enable 33 | #define BUTTON 8 // Button fuer Factory-Reset etc. 34 | 35 | #define ONEWIRE_PIN 10 // Onewire Bus 36 | 37 | #define HEATER_PIN A4 38 | 39 | #define RELAY_1 A3 40 | #define RELAY_2 A5 41 | 42 | #include "FreeRam.h" 43 | #include 44 | HBWSoftwareSerial rs485(RS485_RXD, RS485_TXD); // RX, TX 45 | #endif //USE_HARDWARE_SERIAL 46 | 47 | -------------------------------------------------------------------------------- /HBW-CC-WW-SPktS/HBWSPktS.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Schwingungspaketsteuerung 3 | * 4 | * http://loetmeister.de/Elektronik/homematic/ 5 | * 6 | */ 7 | 8 | #ifndef HBWSPktS_h 9 | #define HBWSPktS_h 10 | 11 | 12 | #include "HBWired.h" 13 | #include "HBWDeltaT.h" 14 | 15 | 16 | #define DEBUG_OUTPUT // debug output on serial/USB 17 | 18 | 19 | // global vars 20 | // volatile unsigned char SPktS_currentValue; 21 | // uint8_t SPktS_outputPin; 22 | inline void setup_timer(); 23 | 24 | static const byte WELLENPAKETSCHRITTE = 25; // 500ms / 20ms (20ms = 1/50Hz) - Anzahl Schritte bei enspr. Paketlänge und Periodendauer 25 | 26 | 27 | // config of SPktS (dimmer) channel, address step 4 28 | struct hbw_config_dim_spkts { 29 | uint8_t logging:1; // send info message on (important) state changes 30 | uint8_t max_output:4; // 20 - 100% (0 = disabled) 31 | uint8_t :3; //fillup 32 | uint8_t max_temp; // 1..254 °C ( 0 = "special value", NOT_USED) 33 | uint8_t auto_off; // 1..254 seconds ( 0 = "special value", NOT_USED) //TODO: change to 10..1270? seconds () 34 | uint8_t dummy; 35 | }; 36 | 37 | 38 | class HBWSPktS : public HBWChannel { 39 | public: 40 | HBWSPktS(uint8_t* _pin, hbw_config_dim_spkts* _config, HBWDeltaTx* _temp1, volatile unsigned char* _SPktS_currentValue); 41 | virtual uint8_t get(uint8_t* data); 42 | virtual void loop(HBWDevice*, uint8_t channel); 43 | virtual void set(HBWDevice*, uint8_t length, uint8_t const * const data); 44 | virtual void afterReadConfig(); 45 | 46 | protected: 47 | uint8_t* pin; 48 | unsigned char currentValue; // keep track of logical state, not real IO 49 | volatile unsigned char* SPktSValue; 50 | uint32_t lastSetTime; 51 | bool initDone; 52 | 53 | private: 54 | hbw_config_dim_spkts* config; 55 | HBWDeltaTx* temp1 = NULL; // linked virtual HBWDeltaTx input channel to receive temperature 56 | 57 | union state_flags { 58 | struct s_state_flags { 59 | uint8_t notUsed :4; // lowest 4 bit are not used, based on XML state_flag definition 60 | uint8_t timeout :1; // max_on_time reached 61 | uint8_t tMax :1; // max temp reached 62 | uint8_t working :1; // true, if working 63 | uint8_t unused :1; 64 | } state; 65 | uint8_t byte:8; 66 | }; 67 | 68 | state_flags stateFlags; 69 | }; 70 | 71 | // These define's must be placed at the beginning before #include "TimerInterrupt.h" 72 | // _TIMERINTERRUPT_LOGLEVEL_ from 0 to 4 73 | // Don't define _TIMERINTERRUPT_LOGLEVEL_ > 0. Only for special ISR debugging only. Can hang the system. 74 | // #define TIMER_INTERRUPT_DEBUG 0 75 | // #define _TIMERINTERRUPT_LOGLEVEL_ 0 76 | 77 | // // Timer0 is used for micros(), millis(), delay(), etc and can't be used 78 | // #define USE_TIMER_1 true 79 | 80 | // // To be included only in main(), .ino with setup() to avoid `Multiple Definitions` Linker Error 81 | // #include "TimerInterrupt.h" 82 | 83 | // void HBWSPktS::setup_timer() // call from main setup() 84 | // { 85 | // cli();//stop interrupts 86 | 87 | // //set timer1 interrupt at 50Hz 88 | // TCCR1A = 0;// set entire TCCR1A register to 0 89 | // TCCR1B = 0;// same for TCCR1B 90 | // TCNT1 = 0;//initialize counter value to 0 91 | // // set compare match register for 1hz increments 92 | // OCR1A = 312;// = (16*10^6) / (50*1024) - 1 (must be <65536) 93 | // // turn on CTC mode 94 | // TCCR1B |= (1 << WGM12); 95 | // // Set CS12 and CS10 bits for 1024 prescaler 96 | // TCCR1B |= (1 << CS12) | (1 << CS10); 97 | // // enable timer compare interrupt 98 | // TIMSK1 |= (1 << OCIE1A); 99 | 100 | // sei();//allow interrupts 101 | // } 102 | 103 | // TODO: put into hpp? 104 | // ISR(TIMER1_COMPA_vect) 105 | // { 106 | // //timer1 interrupt 8kHz 107 | 108 | // static byte WellenpaketCnt = 1; 109 | 110 | // if (SPktS_currentValue && WellenpaketCnt <= SPktS_currentValue) digitalWrite(SPktS_outputPin, true); 111 | // else digitalWrite(SPktS_outputPin, false); 112 | 113 | // if (WellenpaketCnt < WELLENPAKETSCHRITTE) WellenpaketCnt++; 114 | // else WellenpaketCnt = 1; 115 | // } 116 | 117 | // void TimerHandler(unsigned int outputPin) 118 | // { 119 | // static byte WellenpaketCnt = 1; 120 | 121 | // if (SPktS_currentValue && WellenpaketCnt <= SPktS_currentValue) digitalWrite(outputPin, true); 122 | // else digitalWrite(outputPin, false); 123 | 124 | // if (WellenpaketCnt < WELLENPAKETSCHRITTE) WellenpaketCnt++; 125 | // else WellenpaketCnt = 1; 126 | // } 127 | 128 | // #define TIMER_INTERVAL_MS 20 129 | 130 | 131 | #endif /* HBWSPktS_h */ 132 | -------------------------------------------------------------------------------- /HBW-CC-WW-SPktS/readme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThorstenPferdekaemper/HBWired/27cbac299529a660c791c42f2cece74439513561/HBW-CC-WW-SPktS/readme.txt -------------------------------------------------------------------------------- /HBW-DIS-Key-4/HBW-DIS-Key-4_config_example.h: -------------------------------------------------------------------------------- 1 | /* Default / example configuation file. When using custom device config (pinout, EEPROM, etc.) or controller, 2 | * copy this file and adjust it. This would also avoid to owerwrite it with new versions from GitHub. */ 3 | 4 | // Arduino NANO / ATMega 328p config - RS485 bus is attached to SoftwareSerial by default, UART0 is used for serial debug. 5 | 6 | EEPROMClass* EepromPtr = &EEPROM; // use internal EEPROM 7 | 8 | // #define USE_HARDWARE_SERIAL // use hardware serial (USART) for final device - this disables debug output 9 | /* Undefine "HBW_DEBUG" in 'HBWired.h' to remove unneeded code. "HBW_DEBUG" also works as master switch, 10 | * as hbwdebug() or hbwdebughex() used in channels will point to empty functions. */ 11 | 12 | // Pins 13 | #ifdef USE_HARDWARE_SERIAL 14 | #define RS485_TXEN 2 // Transmit-Enable 15 | #define BUTTON A6 // Button fuer Factory-Reset etc. 16 | #define LED LED_BUILTIN // Signal-LED 17 | 18 | #define BUTTON_1 A0 19 | #define BUTTON_2 A1 20 | #define BUTTON_3 A2 21 | #define BUTTON_4 A3 22 | 23 | #define LCD_RS 12 24 | #define LCD_EN 11 25 | #define LCD_D4 10 26 | #define LCD_D5 9 27 | #define LCD_D6 7 28 | #define LCD_D7 6 29 | 30 | #define LCD_BACKLIGHT_PWM 5 31 | 32 | #define LDR_PIN A7 33 | 34 | // #define BLOCKED_TWI_SDA A4 // used by I²C - SDA 35 | // #define BLOCKED_TWI_SCL A5 // used by I²C - SCL 36 | 37 | #else 38 | #define RS485_RXD 4 39 | #define RS485_TXD 2 40 | #define RS485_TXEN 3 // Transmit-Enable 41 | #define BUTTON 8 // Button fuer Factory-Reset etc. 42 | #define LED LED_BUILTIN // Signal-LED 43 | 44 | #define BUTTON_1 A0 45 | #define BUTTON_2 A1 46 | #define BUTTON_3 A2 47 | #define BUTTON_4 A3 48 | 49 | #define LCD_RS 12 50 | #define LCD_EN 11 51 | #define LCD_D4 10 52 | #define LCD_D5 9 53 | #define LCD_D6 7 54 | #define LCD_D7 6 55 | 56 | #define LCD_BACKLIGHT_PWM 5 57 | 58 | #define LDR_PIN A7 59 | 60 | // #define BLOCKED_TWI_SDA A4 // used by I²C - SDA 61 | // #define BLOCKED_TWI_SCL A5 // used by I²C - SCL 62 | 63 | #include "FreeRam.h" 64 | #include "HBWSoftwareSerial.h" 65 | HBWSoftwareSerial rs485(RS485_RXD, RS485_TXD); // RX, TX 66 | #endif //USE_HARDWARE_SERIAL 67 | 68 | 69 | -------------------------------------------------------------------------------- /HBW-DIS-Key-4/HBWLinkInfoKeyEventActuator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ** HBWLinkInfoKeyEventActuator 3 | ** 4 | ** Einfache direkte Verknuepfung (Peering), zu Schaltausgaengen 5 | ** Ein Link-Objekt steht immer fuer alle (direkt aufeinander folgenden) Verknuepfungen 6 | ** des entsprechenden Typs. 7 | ** 8 | */ 9 | 10 | #include "HBWLinkInfoKeyEventActuator.h" 11 | -------------------------------------------------------------------------------- /HBW-DIS-Key-4/HBWLinkInfoKeyEventActuator.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** HBWLinkInfoKeyEventActuator 3 | ** 4 | ** Einfache direkte Verknuepfung (Peering), zu Schaltausgaengen 5 | ** Ein Link-Objekt steht immer fuer alle (direkt aufeinander folgenden) Verknuepfungen 6 | ** des entsprechenden Typs. 7 | ** 8 | */ 9 | 10 | // TODO: put this back into the normal HBWLinkReceiver - find a good way to combine different classes (without wasting space...) 11 | 12 | #ifndef HBWLinkInfoKeyEventActuator_h 13 | #define HBWLinkInfoKeyEventActuator_h 14 | 15 | #include "HBWired.h" 16 | 17 | 18 | template 19 | class HBWLinkInfoKeyEventActuator : public HBWLinkReceiver { 20 | public: 21 | HBWLinkInfoKeyEventActuator(); 22 | void receiveInfoEvent(HBWDevice* device, uint32_t senderAddress, uint8_t senderChannel, 23 | uint8_t targetChannel, uint8_t length, uint8_t const * const data); 24 | void receiveKeyEvent(HBWDevice* device, uint32_t senderAddress, uint8_t senderChannel, 25 | uint8_t targetChannel, uint8_t keyPressNum, boolean longPress); 26 | private: 27 | uint32_t lastSenderAddress; 28 | uint8_t lastSenderChannel; 29 | 30 | static const uint8_t EEPROM_SIZE = 7; // "address_step" in XML 31 | }; 32 | 33 | #include "HBWLinkInfoKeyEventActuator.hpp" 34 | #endif 35 | -------------------------------------------------------------------------------- /HBW-DIS-Key-4/HBWLinkInfoKeyEventActuator.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | ** HBWLinkInfoKeyEventActuator 3 | ** 4 | ** Einfache direkte Verknuepfung (Peering), zu Schaltausgaengen 5 | ** Ein Link-Objekt steht immer fuer alle (direkt aufeinander folgenden) Verknuepfungen 6 | ** des entsprechenden Typs. 7 | ** 8 | */ 9 | 10 | // TODO: put this back into the normal HBWLinkReceiver - find a good way to combine different classes (without wasting space...) 11 | 12 | #ifdef Support_HBWLink_InfoEvent 13 | template 14 | HBWLinkInfoKeyEventActuator::HBWLinkInfoKeyEventActuator() { 15 | } 16 | 17 | 18 | // TODO: Der Beginn aller Verknuepfungen ist gleich. Eigentlich koennte man 19 | // das meiste in einer gemeinsamen Basisklasse abhandeln 20 | template 21 | void HBWLinkInfoKeyEventActuator::receiveInfoEvent(HBWDevice* device, uint32_t senderAddress, uint8_t senderChannel, 22 | uint8_t targetChannel, uint8_t length, uint8_t const * const data) { 23 | 24 | uint32_t sndAddrEEPROM; 25 | uint8_t channelEEPROM; 26 | 27 | // read what to do from EEPROM 28 | for(byte i = 0; i < numLinks; i++) { 29 | device->readEEPROM(&sndAddrEEPROM, eepromStart + EEPROM_SIZE * i, 4, true); 30 | // TODO: is the following really ok? 31 | // it reads to all links, even if none is set 32 | if(sndAddrEEPROM == 0xFFFFFFFF) continue; 33 | if(sndAddrEEPROM != senderAddress) continue; 34 | // compare sender channel 35 | device->readEEPROM(&channelEEPROM, eepromStart + EEPROM_SIZE * i + 4, 1); 36 | if(channelEEPROM != senderChannel) continue; 37 | // compare target channel 38 | device->readEEPROM(&channelEEPROM, eepromStart + EEPROM_SIZE * i + 5, 1); 39 | if(channelEEPROM != targetChannel) continue; 40 | // ok, we have found a match 41 | 42 | 43 | device->setInfo(targetChannel, length, data); // channel, data length, data 44 | } 45 | } 46 | template 47 | void HBWLinkInfoKeyEventActuator::receiveKeyEvent(HBWDevice* device, uint32_t senderAddress, uint8_t senderChannel, 48 | uint8_t targetChannel, uint8_t keyPressNum, boolean longPress) { 49 | 50 | uint32_t sndAddrEEPROM; 51 | uint8_t channelEEPROM; 52 | uint8_t actionType; 53 | uint8_t data[3]; 54 | data[1] = keyPressNum; 55 | data[2] = false; 56 | 57 | if (senderAddress == lastSenderAddress && senderChannel == lastSenderChannel) { 58 | data[2] = true; // true, as this was the same sender (source device & channel) - sameLastSender 59 | } 60 | lastSenderAddress = senderAddress; 61 | lastSenderChannel = senderChannel; 62 | 63 | // read what to do from EEPROM 64 | for(byte i = 0; i < numLinks; i++) { 65 | device->readEEPROM(&sndAddrEEPROM, eepromStart + EEPROM_SIZE * i, 4, true); 66 | // TODO: is the following really ok? 67 | // it reads to all links, even if none is set 68 | if(sndAddrEEPROM == 0xFFFFFFFF) continue; 69 | if(sndAddrEEPROM != senderAddress) continue; 70 | // compare sender channel 71 | device->readEEPROM(&channelEEPROM, eepromStart + EEPROM_SIZE * i + 4, 1); 72 | if(channelEEPROM != senderChannel) continue; 73 | // compare target channel 74 | device->readEEPROM(&channelEEPROM, eepromStart + EEPROM_SIZE * i + 5, 1); 75 | if(channelEEPROM != targetChannel) continue; 76 | // ok, we have found a match 77 | // read actionType 78 | device->readEEPROM(&actionType, eepromStart + EEPROM_SIZE * i + 6, 1); 79 | // differs for short and long 80 | if (longPress) actionType >>= 2; 81 | actionType &= B00000011; 82 | //uint8_t data; 83 | // we can have 84 | switch(actionType) { 85 | // 0 -> ON 86 | case 0: data[0] = 200; 87 | break; 88 | // 1 -> OFF 89 | case 1: data[0] = 0; 90 | break; 91 | // 2 -> INACTIVE 92 | case 2: continue; 93 | // 3 -> TOGGLE (default) 94 | case 3: data[0] = 255; 95 | // break; 96 | }; 97 | device->set(targetChannel, sizeof(data),data); // channel, data length, data 98 | } 99 | } 100 | #endif 101 | -------------------------------------------------------------------------------- /HBW-DIS-Key-4/readme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThorstenPferdekaemper/HBWired/27cbac299529a660c791c42f2cece74439513561/HBW-DIS-Key-4/readme.txt -------------------------------------------------------------------------------- /HBW-LC-BL-4/HBW-LC-BL-4_config_example.h: -------------------------------------------------------------------------------- 1 | /* Default / example configuation file. When using custom device config (pinout, EEPROM, etc.) or controller, 2 | * copy this file and adjust it. This would also avoid to owerwrite it with new versions from GitHub. */ 3 | 4 | // Arduino NANO / ATMega 328p config - RS485 bus is attached to SoftwareSerial by default, UART0 is used for serial debug. 5 | 6 | EEPROMClass* EepromPtr = &EEPROM; // use internal EEPROM 7 | 8 | // #define USE_HARDWARE_SERIAL // use hardware serial (USART) for final device - this disables debug output 9 | /* Undefine "HBW_DEBUG" in 'HBWired.h' to remove unneeded code. "HBW_DEBUG" also works as master switch, 10 | * as hbwdebug() or hbwdebughex() used in channels will point to empty functions. */ 11 | 12 | // Pins 13 | #ifdef USE_HARDWARE_SERIAL 14 | #define RS485_TXEN 2 // Transmit-Enable 15 | 16 | #else 17 | #define RS485_RXD 4 18 | #define RS485_TXD 2 19 | #define RS485_TXEN 3 // Transmit-Enable 20 | 21 | #include 22 | #include 23 | HBWSoftwareSerial rs485(RS485_RXD, RS485_TXD); // RX, TX 24 | #endif 25 | 26 | #define BUTTON 8 // Button fuer Factory-Reset etc. 27 | #define LED LED_BUILTIN // Signal-LED 28 | 29 | #define BLIND1_ACT 5 // "Ein-/Aus-Relais" 30 | #define BLIND1_DIR 6 // "Richungs-Relais" 31 | #define BLIND2_ACT A0 32 | #define BLIND2_DIR A1 33 | #define BLIND3_ACT A2 34 | #define BLIND3_DIR A3 35 | #define BLIND4_ACT A4 36 | #define BLIND4_DIR A5 37 | 38 | #define ADC_BUS_VOLTAGE A7 // analog input to measure bus voltage (using internal 1.1 volt reference) 39 | 40 | inline void SetupHardware() 41 | { 42 | #if defined (ADC_BUS_VOLTAGE) 43 | analogReference(INTERNAL); // select internal 1.1 volt reference (to measure external bus voltage) 44 | #endif 45 | }; 46 | 47 | -------------------------------------------------------------------------------- /HBW-LC-BL-4/readme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThorstenPferdekaemper/HBWired/27cbac299529a660c791c42f2cece74439513561/HBW-LC-BL-4/readme.txt -------------------------------------------------------------------------------- /HBW-LC-BL-8/HBW-LC-BL-8_config_example.h: -------------------------------------------------------------------------------- 1 | /* Default / example configuation file. When using custom device config (pinout, EEPROM, etc.) or controller, 2 | * copy this file and adjust it. This would also avoid to owerwrite it with new versions from GitHub. */ 3 | 4 | // Arduino NANO / ATMega 328p config - RS485 bus is attached to UART0. No serial debug available. 5 | 6 | EEPROMClass* EepromPtr = &EEPROM; // use internal EEPROM 7 | 8 | /* Undefine "HBW_DEBUG" in 'HBWired.h' to remove unneeded code. "HBW_DEBUG" also works as master switch, 9 | * as hbwdebug() or hbwdebughex() used in channels will point to empty functions. */ 10 | 11 | // Pins 12 | #define RS485_TXEN 2 // Transmit-Enable 13 | 14 | #define BUTTON A6 // Button fuer Factory-Reset etc. 15 | #define LED LED_BUILTIN // Signal-LED 16 | 17 | #define BLIND1_ACT 10 // "Ein-/Aus-Relais" 18 | #define BLIND1_DIR 9 // "Richungs-Relais" 19 | #define BLIND2_ACT 8 20 | #define BLIND2_DIR 7 21 | #define BLIND3_ACT 6 22 | #define BLIND3_DIR 5 23 | #define BLIND4_ACT 4 24 | #define BLIND4_DIR 3 25 | 26 | #define BLIND5_ACT A5 27 | #define BLIND5_DIR A4 28 | #define BLIND6_ACT A2 29 | #define BLIND6_DIR A3 30 | #define BLIND7_ACT A1 31 | #define BLIND7_DIR A0 32 | #define BLIND8_ACT 11 33 | #define BLIND8_DIR 12 34 | 35 | #define ADC_BUS_VOLTAGE A7 // analog input to measure bus voltage (using internal 1.1 volt reference) 36 | 37 | inline void SetupHardware() 38 | { 39 | #if defined (ADC_BUS_VOLTAGE) 40 | analogReference(INTERNAL); // select internal 1.1 volt reference (to measure external bus voltage) 41 | #endif 42 | }; 43 | -------------------------------------------------------------------------------- /HBW-LC-BL-8/readme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThorstenPferdekaemper/HBWired/27cbac299529a660c791c42f2cece74439513561/HBW-LC-BL-8/readme.txt -------------------------------------------------------------------------------- /HBW-LC-Sw-12/HBW-LC-Sw-12_config_example.h: -------------------------------------------------------------------------------- 1 | /* Default / example configuation file. When using custom device config (pinout, EEPROM, etc.) or controller, 2 | * copy this file and adjust it. This would also avoid to owerwrite it with new versions from GitHub. */ 3 | 4 | // Arduino NANO / ATMega 328p config - RS485 bus is attached to SoftwareSerial by default, UART0 is used for serial debug. 5 | 6 | EEPROMClass* EepromPtr = &EEPROM; // use internal EEPROM 7 | 8 | // #define USE_HARDWARE_SERIAL // use hardware serial (USART) for final device - this disables debug output 9 | /* Undefine "HBW_DEBUG" in 'HBWired.h' to remove unneeded code. "HBW_DEBUG" also works as master switch, 10 | * as hbwdebug() or hbwdebughex() used in channels will point to empty functions. */ 11 | 12 | 13 | // Pins 14 | #ifdef USE_HARDWARE_SERIAL 15 | #define BUTTON A6 // Button fuer Factory-Reset etc. 16 | #define RS485_TXEN 2 // Transmit-Enable 17 | #define shiftReg_OutputEnable 8 // OE output enable, connect to all shift register 18 | // 6 realys and LED attached to 3 shiftregisters 19 | #define shiftRegOne_Data 10 //DS serial data input 20 | #define shiftRegOne_Clock 3 //SH_CP shift register clock input 21 | #define shiftRegOne_Latch 4 //ST_CP storage register clock input 22 | // extension shifregister for another 6 relays and LEDs 23 | #define shiftRegTwo_Data 7 24 | #define shiftRegTwo_Clock 12 25 | #define shiftRegTwo_Latch 9 26 | 27 | #else 28 | #define BUTTON 8 // Button fuer Factory-Reset etc. 29 | #define RS485_RXD 4 30 | #define RS485_TXD 2 31 | #define RS485_TXEN 3 // Transmit-Enable 32 | #define shiftReg_OutputEnable 12 // OE output enable, connect to all shift register 33 | // 6 realys and LED attached to 3 shiftregisters 34 | #define shiftRegOne_Data 10 //DS serial data input 35 | #define shiftRegOne_Clock 9 //SH_CP shift register clock input 36 | #define shiftRegOne_Latch 11 //ST_CP storage register clock input 37 | // extension shifregister for another 6 relays and LEDs 38 | #define shiftRegTwo_Data 5 39 | #define shiftRegTwo_Clock 7 40 | #define shiftRegTwo_Latch 6 41 | 42 | #include 43 | #include 44 | HBWSoftwareSerial rs485(RS485_RXD, RS485_TXD); // RX, TX 45 | #endif 46 | 47 | #define LED LED_BUILTIN // Signal-LED 48 | 49 | #define CT_PIN1 A0 // analog input for current transformer, switch channel 1 50 | #define CT_PIN2 A1 // analog input for current transformer, switch channel 2 51 | #define CT_PIN3 A2 52 | #define CT_PIN4 A4 53 | #define CT_PIN5 A5 54 | #define CT_PIN6 A3 55 | 56 | 57 | -------------------------------------------------------------------------------- /HBW-LC-Sw-12/HBWAnalogPow.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * HBWAnalogPow.cpp 3 | * 4 | * analog power meter input channel, using current transformers connected to ADC 5 | * 6 | * Updated: 02.04.2019 7 | * www.loetmeister.de 8 | * 9 | */ 10 | 11 | #include "HBWAnalogPow.h" 12 | 13 | // Class HBWAnalogPow 14 | HBWAnalogPow::HBWAnalogPow(uint8_t _pin, hbw_config_analogPow_in* _config) { 15 | pin = _pin; 16 | config = _config; 17 | lastActionTime = 0; 18 | nextActionDelay = MIN_UPDATE_INTERVAL *2; // initial dealy 19 | currentValue = 0; 20 | analogRead(pin); 21 | }; 22 | 23 | 24 | // channel specific settings or defaults 25 | //void HBWAnalogPow::afterReadConfig() { 26 | // 27 | //}; 28 | 29 | 30 | /* standard public function - returns length of data array. Data array contains current channel reading */ 31 | uint8_t HBWAnalogPow::get(uint8_t* data) { 32 | 33 | // MSB first 34 | *data++ = (currentValue >> 8); 35 | *data = currentValue & 0xFF; 36 | return 2; 37 | }; 38 | 39 | 40 | /* standard public function - called by main loop for every channel in sequential order */ 41 | void HBWAnalogPow::loop(HBWDevice* device, uint8_t channel) { 42 | 43 | if (config->input_disabled) { // skip disabled channels 44 | currentValue = 0; 45 | return; 46 | } 47 | 48 | if (millis() - lastActionTime < ((uint32_t)nextActionDelay )) return; // quit if wait time not yet passed 49 | 50 | //TODO: make it work :) 51 | // perform measurement in port interrupt function triggered by mains opto = mains frequency? (consider different phases 120°, 240° phase shift? - don't care if covering full sinus wave?) 52 | // use global buffer and run run ADC conversion for one channel at a time, with fixed amount of samples, to cover full sin wave 53 | // approach 1: run all samples at one interrupt (block device for 1/50Hz) or 2: run one sample per interrupt (50Hz), but delay a bit each time, to cover full sin wave 54 | // disable interrupt until channel fetched result and next channel should be started? 55 | 56 | // use I²C ADC? how to buffer or run continous measurement? 57 | 58 | nextActionDelay = SAMPLE_INTERVAL; 59 | #define MAX_SAMPLES 6 // update "buffer" array definition, when changing this! 60 | static uint8_t buffer[MAX_SAMPLES] = {0, 0, 0, 0, 0, 0}; 61 | static uint8_t nextIndex = 0; 62 | 63 | uint16_t adcReading = analogRead(pin); 64 | if (adcReading < CENTRE_VALUE) { 65 | adcReading = CENTRE_VALUE - adcReading; 66 | } 67 | else 68 | { 69 | adcReading = adcReading - CENTRE_VALUE; 70 | } 71 | buffer[nextIndex++] = (uint8_t)(adcReading >>2);//analogRead(pin); 72 | lastActionTime = millis(); 73 | 74 | if (nextIndex >= MAX_SAMPLES) { 75 | nextIndex = 0; 76 | uint32_t sum = 0; 77 | uint8_t i = MAX_SAMPLES; 78 | do { 79 | sum += buffer[--i]; 80 | } 81 | while (i); 82 | 83 | currentValue = sum / MAX_SAMPLES; 84 | // nextActionDelay = UPDATE_INTERVAL; // "sleep" until next update 85 | nextActionDelay = (config->update_interval < 1) ? MIN_UPDATE_INTERVAL : (uint16_t)(config->update_interval * 1000); // "sleep" until next update 86 | 87 | #ifdef DEBUG_OUTPUT 88 | hbwdebug(F("adc-ch:")); 89 | hbwdebug(channel); 90 | hbwdebug(F(" Val:")); 91 | hbwdebug(currentValue); 92 | hbwdebug(F("\n")); 93 | #endif 94 | } 95 | }; 96 | -------------------------------------------------------------------------------- /HBW-LC-Sw-12/HBWAnalogPow.h: -------------------------------------------------------------------------------- 1 | /* 2 | * HBWAnalogPow.cpp 3 | * 4 | * analog power meter input channel, using current transformers connected to ADC 5 | * 6 | * www.loetmeister.de 7 | * 8 | */ 9 | 10 | #ifndef HBWAnalogPow_h 11 | #define HBWAnalogPow_h 12 | 13 | #include 14 | #include "HBWired.h" 15 | 16 | 17 | //#define DEBUG_OUTPUT // extra debug output on serial/USB 18 | 19 | #define SAMPLE_INTERVAL 6 // milli seconds 20 | constexpr uint16_t MIN_UPDATE_INTERVAL = 1000; // milli seconds 21 | constexpr uint16_t CENTRE_VALUE = 511; // sin wave centre 22 | 23 | 24 | struct hbw_config_analogPow_in { 25 | uint8_t input_disabled:1; // +0:0 1=DISABLED (default), 0=ENABLED 26 | uint8_t notify_disabled:1; // +0:1 1=DISABLED (default), 0=ENABLED 27 | uint8_t :6; // 0x00:2-7 28 | uint8_t update_interval; 29 | //TODO: Add compensation factor? (increase accurrancy)? - replace CENTRE_VALUE? 30 | //TODO: Add phase selection (to consider 120°, 240° phase shift from optocoupler input)? 31 | }; 32 | 33 | 34 | // Class HBWAnalogPow 35 | class HBWAnalogPow : public HBWChannel { 36 | public: 37 | HBWAnalogPow(uint8_t _pin, hbw_config_analogPow_in* _config); 38 | virtual uint8_t get(uint8_t* data); 39 | virtual void loop(HBWDevice*, uint8_t channel); 40 | // virtual void afterReadConfig(); 41 | 42 | private: 43 | uint8_t pin; // Pin 44 | hbw_config_analogPow_in* config; 45 | uint32_t lastActionTime; 46 | uint16_t nextActionDelay; 47 | uint16_t currentValue; // store last result (average) 48 | }; 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /HBW-LC-Sw-12/HBWSwitchSerialAdvanced.h: -------------------------------------------------------------------------------- 1 | /* 2 | * HBWSwitchSerialAdvanced.h 3 | * 4 | * Ansteuerung von bistabilen Relais über Shiftregister 5 | * 6 | * Als Alternative zu HBWSwitch & HBWLinkSwitchSimple sind mit 7 | * HBWSwitchAdvanced & HBWLinkSwitchAdvanced folgende Funktionen möglich: 8 | * Peering mit TOGGLE, TOGGLE_TO_COUNTER, TOGGLE_INVERSE_TO_COUNTER, onTime, 9 | * offTime (Ein-/Ausschaltdauer), onDelayTime, offDelayTime (Ein-/Ausschaltverzögerung). 10 | * 11 | * Updated: 29.12.2024 12 | * 13 | * http://loetmeister.de/Elektronik/homematic/index.htm#modules 14 | */ 15 | 16 | #ifndef HBWSwitchSerialAdvanced_h 17 | #define HBWSwitchSerialAdvanced_h 18 | 19 | #include 20 | #include // derive from this class 21 | #include "ShiftRegister74HC595.h" // shift register library, slightly customized 22 | 23 | // #define DEBUG_OUTPUT // extra debug output on serial/USB 24 | 25 | 26 | #define SHIFT_REGISTER_CLASS ShiftRegister74HC595<3> // Daisy chain 3 registers 27 | 28 | #define RELAY_PULSE_DUARTION 80 // HIGH duration in ms, to set or reset double coil latching relay safely 29 | 30 | #define OFF false 31 | #define ON true 32 | 33 | 34 | class HBWSwitchSerialAdvanced : public HBWSwitchAdvanced { 35 | public: 36 | HBWSwitchSerialAdvanced(uint8_t _relayPos, uint8_t _ledPos, SHIFT_REGISTER_CLASS* _shiftRegister, hbw_config_switch* _config); 37 | virtual uint8_t get(uint8_t* data); 38 | virtual void loop(HBWDevice*, uint8_t channel); 39 | // virtual void set(HBWDevice*, uint8_t length, uint8_t const * const data); - use parent 40 | virtual void afterReadConfig(); 41 | 42 | private: 43 | uint8_t relayPos; // bit position for actual IO port 44 | uint8_t ledPos; 45 | SHIFT_REGISTER_CLASS* shiftRegister; // allow function calls to the correct shift register 46 | virtual bool setOutput(HBWDevice*, uint8_t newstate); 47 | 48 | protected: 49 | bool relayOperationPending; 50 | bool relayLevel; // current logical level 51 | void operateRelay(bool _newLevel); 52 | uint32_t relayOperationTimeStart; 53 | }; 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /HBW-LC-Sw-12/ShiftRegister74HC595.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ShiftRegister74HC595.cpp - Library for simplified control of 74HC595 shift registers. 3 | Developed and maintained by Timo Denk and contributers, since Nov 2014. 4 | Additional information is available at https://timodenk.com/blog/shift-register-arduino-library/ 5 | Released into the public domain. 6 | */ 7 | 8 | #include 9 | #include "ShiftRegister74HC595.h" 10 | -------------------------------------------------------------------------------- /HBW-LC-Sw-12/ShiftRegister74HC595.h: -------------------------------------------------------------------------------- 1 | /* 2 | ShiftRegister74HC595.h - Library for simplified control of 74HC595 shift registers. 3 | Developed and maintained by Timo Denk and contributers, since Nov 2014. 4 | Additional information is available at https://timodenk.com/blog/shift-register-arduino-library/ 5 | Released into the public domain. 6 | version 1.3.1 7 | */ 8 | 9 | #pragma once 10 | 11 | #include 12 | 13 | template 14 | class ShiftRegister74HC595 15 | { 16 | public: 17 | ShiftRegister74HC595(const uint8_t serialDataPin, const uint8_t clockPin, const uint8_t latchPin); 18 | 19 | void setAll(const uint8_t * digitalValues); 20 | #ifdef __AVR__ 21 | void setAll_P(const uint8_t * digitalValuesProgmem); // Experimental, PROGMEM data 22 | #endif 23 | uint8_t * getAll(); 24 | void set(const uint8_t pin, const uint8_t value); 25 | void setNoUpdate(const uint8_t pin, uint8_t value); 26 | void updateRegisters(); 27 | void setAllLow(); 28 | void setAllHigh(); 29 | uint8_t get(const uint8_t pin); 30 | 31 | private: 32 | uint8_t _clockPin; 33 | uint8_t _serialDataPin; 34 | uint8_t _latchPin; 35 | 36 | uint8_t _digitalValues[Size]; 37 | }; 38 | 39 | #include "ShiftRegister74HC595.hpp" 40 | -------------------------------------------------------------------------------- /HBW-LC-Sw-12/ShiftRegister74HC595.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | ShiftRegister74HC595.hpp - Library for simplified control of 74HC595 shift registers. 3 | Developed and maintained by Timo Denk and contributers, since Nov 2014. 4 | Additional information is available at https://timodenk.com/blog/shift-register-arduino-library/ 5 | Released into the public domain. 6 | */ 7 | 8 | // ShiftRegister74HC595 constructor 9 | // Size is the number of shiftregisters stacked in serial 10 | template 11 | ShiftRegister74HC595::ShiftRegister74HC595(const uint8_t serialDataPin, const uint8_t clockPin, const uint8_t latchPin) 12 | { 13 | // set attributes 14 | _clockPin = clockPin; 15 | _serialDataPin = serialDataPin; 16 | _latchPin = latchPin; 17 | 18 | // define pins as outputs 19 | pinMode(clockPin, OUTPUT); 20 | pinMode(serialDataPin, OUTPUT); 21 | pinMode(latchPin, OUTPUT); 22 | 23 | // set pins low 24 | digitalWrite(clockPin, LOW); 25 | digitalWrite(serialDataPin, LOW); 26 | digitalWrite(latchPin, LOW); 27 | 28 | // allocates the specified number of bytes and initializes them to zero 29 | //memset(_digitalValues, 0, Size * sizeof(uint8_t)); 30 | 31 | //updateRegisters(); // reset shift register 32 | 33 | setAllLow(); 34 | } 35 | 36 | // Set all pins of the shift registers at once. 37 | // digitalVAlues is a uint8_t array where the length is equal to the number of shift registers. 38 | template 39 | void ShiftRegister74HC595::setAll(const uint8_t * digitalValues) 40 | { 41 | memcpy( _digitalValues, digitalValues, Size); // dest, src, size 42 | updateRegisters(); 43 | } 44 | 45 | // Experimental 46 | // The same as setAll, but the data is located in PROGMEM 47 | // For example with: 48 | // const uint8_t myFlashData[] PROGMEM = { 0x0F, 0x81 }; 49 | #ifdef __AVR__ 50 | template 51 | void ShiftRegister74HC595::setAll_P(const uint8_t * digitalValuesProgmem) 52 | { 53 | PGM_VOID_P p = reinterpret_cast(digitalValuesProgmem); 54 | memcpy_P( _digitalValues, p, Size); 55 | updateRegisters(); 56 | } 57 | #endif 58 | 59 | // Retrieve all states of the shift registers' output pins. 60 | // The returned array's length is equal to the number of shift registers. 61 | template 62 | uint8_t * ShiftRegister74HC595::getAll() 63 | { 64 | return _digitalValues; 65 | } 66 | 67 | // Set a specific pin to either HIGH (1) or LOW (0). 68 | // The pin parameter is a positive, zero-based integer, indicating which pin to set. 69 | template 70 | void ShiftRegister74HC595::set(const uint8_t pin, const uint8_t value) 71 | { 72 | setNoUpdate(pin, value); 73 | updateRegisters(); 74 | } 75 | 76 | // Updates the shift register pins to the stored output values. 77 | // This is the function that actually writes data into the shift registers of the 74HC595. 78 | template 79 | void ShiftRegister74HC595::updateRegisters() 80 | { 81 | for (int i = Size - 1; i >= 0; i--) { 82 | shiftOut(_serialDataPin, _clockPin, MSBFIRST, _digitalValues[i]); 83 | } 84 | 85 | digitalWrite(_latchPin, HIGH); 86 | digitalWrite(_latchPin, LOW); 87 | } 88 | 89 | // Equivalent to set(int pin, uint8_t value), except the physical shift register is not updated. 90 | // Should be used in combination with updateRegisters(). 91 | template 92 | void ShiftRegister74HC595::setNoUpdate(const uint8_t pin, const uint8_t value) 93 | { 94 | (value) ? bitSet(_digitalValues[pin / 8], pin % 8) : bitClear(_digitalValues[pin / 8], pin % 8); 95 | } 96 | 97 | // Returns the state of the given pin. 98 | // Either HIGH (1) or LOW (0) 99 | template 100 | uint8_t ShiftRegister74HC595::get(const uint8_t pin) 101 | { 102 | return (_digitalValues[pin / 8] >> (pin % 8)) & 1; 103 | } 104 | 105 | // Sets all pins of all shift registers to HIGH (1). 106 | template 107 | void ShiftRegister74HC595::setAllHigh() 108 | { 109 | for (int i = 0; i < Size; i++) { 110 | _digitalValues[i] = 255; 111 | } 112 | updateRegisters(); 113 | } 114 | 115 | // Sets all pins of all shift registers to LOW (0). 116 | template 117 | void ShiftRegister74HC595::setAllLow() 118 | { 119 | for (int i = 0; i < Size; i++) { 120 | _digitalValues[i] = 0; 121 | } 122 | updateRegisters(); 123 | } 124 | -------------------------------------------------------------------------------- /HBW-LC-Sw-12/readme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThorstenPferdekaemper/HBWired/27cbac299529a660c791c42f2cece74439513561/HBW-LC-Sw-12/readme.txt -------------------------------------------------------------------------------- /HBW-LC-Sw-8/HBW-LC-Sw-8.ino: -------------------------------------------------------------------------------- 1 | //******************************************************************* 2 | // 3 | // HBW-LC-Sw-8 4 | // 5 | // Homematic Wired Hombrew Hardware 6 | // Arduino NANO als Homematic-Device 7 | // - Active HIGH oder LOW kann konfiguriert werden 8 | // 9 | // http://loetmeister.de/Elektronik/homematic/index.htm#modules 10 | // 11 | //******************************************************************* 12 | // Changes 13 | // v1.01 14 | // - Switch code in "HBWSwitch.h" channel library übertragen. neu: initConfigPins() 15 | // v1.02 16 | // - channel invert angepasst um nach einem Device reset (EEPROM 'gelöscht') keine Invertierung zu haben 17 | // - fix: initConfigPins() in afterReadConfig() geändert. 18 | 19 | 20 | #define HARDWARE_VERSION 0x00 21 | #define FIRMWARE_VERSION 0x0066 22 | #define HMW_DEVICETYPE 0x83 23 | 24 | #define NUM_CHANNELS 8 25 | #define NUM_LINKS 36 26 | #define LINKADDRESSSTART 0x40 27 | 28 | 29 | // HB Wired protocol and module 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | 36 | // Pins and hardware config 37 | #include "HBW-LC-Sw-8_config_example.h" // When using custom device pinout or controller, copy this file and include it instead 38 | 39 | 40 | struct hbw_config { 41 | uint8_t logging_time; // 0x01 42 | uint32_t central_address; // 0x02 - 0x05 43 | uint8_t direct_link_deactivate:1; // 0x06:0 44 | uint8_t :7; // 0x06:1-7 45 | hbw_config_switch switchCfg[NUM_CHANNELS]; // 0x07-0x... ? (address step 2) 46 | } hbwconfig; 47 | 48 | 49 | // create channel object for the switches 50 | HBWSwitch* switches[NUM_CHANNELS]; 51 | 52 | 53 | class HBSwDevice : public HBWDevice { 54 | public: 55 | HBSwDevice(uint8_t _devicetype, uint8_t _hardware_version, uint16_t _firmware_version, 56 | Stream* _rs485, uint8_t _txen, 57 | uint8_t _configSize, void* _config, 58 | uint8_t _numChannels, HBWChannel** _channels, 59 | Stream* _debugstream, HBWLinkSender* linksender = NULL, HBWLinkReceiver* linkreceiver = NULL) : 60 | HBWDevice(_devicetype, _hardware_version, _firmware_version, 61 | _rs485, _txen, _configSize, _config, _numChannels, ((HBWChannel**)(_channels)), 62 | _debugstream, linksender, linkreceiver) { 63 | }; 64 | virtual void afterReadConfig(); 65 | }; 66 | 67 | // device specific defaults 68 | void HBSwDevice::afterReadConfig() { 69 | if(hbwconfig.logging_time == 0xFF) hbwconfig.logging_time = 50; 70 | }; 71 | 72 | 73 | HBSwDevice* device = NULL; 74 | 75 | 76 | 77 | void setup() 78 | { 79 | #ifdef USE_HARDWARE_SERIAL 80 | Serial.begin(19200, SERIAL_8E1); 81 | #else 82 | Serial.begin(115200); // Serial->USB for debug 83 | rs485.begin(); // RS485 via SoftwareSerial, uses 19200 baud! 84 | #endif 85 | 86 | // create channels 87 | static const uint8_t pins[NUM_CHANNELS] = {SWITCH1_PIN, SWITCH2_PIN, SWITCH3_PIN, SWITCH4_PIN, SWITCH5_PIN, SWITCH6_PIN, SWITCH7_PIN, SWITCH8_PIN}; 88 | 89 | // assing switches (relay) pins to channels 90 | for(uint8_t i = 0; i < NUM_CHANNELS; i++) { 91 | switches[i] = new HBWSwitch(pins[i], &(hbwconfig.switchCfg[i])); 92 | } 93 | 94 | device = new HBSwDevice(HMW_DEVICETYPE, HARDWARE_VERSION, FIRMWARE_VERSION, 95 | #ifdef USE_HARDWARE_SERIAL 96 | &Serial, 97 | #else 98 | &rs485, 99 | #endif 100 | RS485_TXEN, sizeof(hbwconfig), &hbwconfig, 101 | NUM_CHANNELS, (HBWChannel**)switches, 102 | #ifdef USE_HARDWARE_SERIAL // set _debugstream to NULL 103 | NULL, 104 | #else 105 | &Serial, 106 | #endif 107 | NULL, new HBWLinkSwitchSimple()); 108 | 109 | device->setConfigPins(BUTTON, LED); // 8 and 13 is the default 110 | 111 | 112 | #ifndef USE_HARDWARE_SERIAL 113 | hbwdebug(F("B: 2A ")); 114 | hbwdebug(freeRam()); 115 | hbwdebug(F("\n")); 116 | #endif 117 | } 118 | 119 | 120 | void loop() 121 | { 122 | device->loop(); 123 | }; 124 | -------------------------------------------------------------------------------- /HBW-LC-Sw-8/HBW-LC-Sw-8_config_example.h: -------------------------------------------------------------------------------- 1 | /* Default / example configuation file. When using custom device config (pinout, EEPROM, etc.) or controller, 2 | * copy this file and adjust it. This would also avoid to owerwrite it with new versions from GitHub. */ 3 | 4 | // Arduino NANO / ATMega 328p config - RS485 bus is attached to SoftwareSerial by default, UART0 is used for serial debug. 5 | 6 | EEPROMClass* EepromPtr = &EEPROM; // use internal EEPROM 7 | 8 | // #define USE_HARDWARE_SERIAL // use hardware serial (USART) for final device - this disables debug output 9 | /* Undefine "HBW_DEBUG" in 'HBWired.h' to remove unneeded code. "HBW_DEBUG" also works as master switch, 10 | * as hbwdebug() or hbwdebughex() used in channels will point to empty functions. */ 11 | 12 | 13 | // Pins 14 | #ifdef USE_HARDWARE_SERIAL 15 | #define RS485_TXEN 2 // Transmit-Enable 16 | 17 | #else 18 | #define RS485_RXD 4 19 | #define RS485_TXD 2 20 | #define RS485_TXEN 3 // Transmit-Enable 21 | 22 | #include 23 | #include 24 | HBWSoftwareSerial rs485(RS485_RXD, RS485_TXD); // RX, TX 25 | #endif 26 | 27 | 28 | #define BUTTON 8 // Button fuer Factory-Reset etc. 29 | #define LED LED_BUILTIN // Signal-LED 30 | #define SWITCH1_PIN A0 // Ausgangpins fuer die Relais 31 | #define SWITCH2_PIN A1 32 | #define SWITCH3_PIN A2 33 | #define SWITCH4_PIN A3 34 | #define SWITCH5_PIN A4 35 | #define SWITCH6_PIN A5 36 | #define SWITCH7_PIN 10 37 | #define SWITCH8_PIN 11 38 | 39 | -------------------------------------------------------------------------------- /HBW-LC-Sw-8/readme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThorstenPferdekaemper/HBWired/27cbac299529a660c791c42f2cece74439513561/HBW-LC-Sw-8/readme.txt -------------------------------------------------------------------------------- /HBW-LC-Sw-8_AdvancedPeering/HBW-LC-Sw-8_AdvancedPeering.ino: -------------------------------------------------------------------------------- 1 | //******************************************************************* 2 | // 3 | // HBW-LC-Sw-8 4 | // 5 | // Homematic Wired Hombrew Hardware 6 | // Arduino NANO als Homematic-Device 7 | // - Active HIGH oder LOW kann konfiguriert werden 8 | // 9 | // http://loetmeister.de/Elektronik/homematic/index.htm#modules 10 | // 11 | //******************************************************************* 12 | // Changes 13 | // v1.01 14 | // - Switch code in "HBWSwitch.h" channel library übertragen. neu: initConfigPins() 15 | // v1.02 16 | // - channel invert angepasst um nach einem Device reset (EEPROM 'gelöscht') keine Invertierung zu haben 17 | // - fix: initConfigPins() in afterReadConfig() geändert. 18 | // v1.03 19 | // - erweitertes peering hinzugefügt (HBWLinkSwitchAdvanced.h, HBWSwitchAdvanced.h) - Benötigt passende XML! 20 | // v1.04 21 | // - state flag added 22 | // v1.1 23 | // - internal rework of state engine (using https://github.com/pa-pa/AskSinPP) 24 | 25 | 26 | #define HARDWARE_VERSION 0x01 27 | #define FIRMWARE_VERSION 0x0072 28 | #define HMW_DEVICETYPE 0x83 29 | 30 | #define NUM_CHANNELS 8 31 | #define NUM_LINKS 36 32 | #define LINKADDRESSSTART 0x40 33 | 34 | 35 | // HB Wired protocol and module 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | 42 | // Pins and hardware config 43 | #include "HBW-LC-Sw-8_AdvancedPeering_config_example.h" // When using custom device pinout or controller, copy this file and include it instead 44 | 45 | 46 | struct hbw_config { 47 | uint8_t logging_time; // 0x01 48 | uint32_t central_address; // 0x02 - 0x05 49 | uint8_t direct_link_deactivate:1; // 0x06:0 50 | uint8_t :7; // 0x06:1-7 51 | hbw_config_switch switchCfg[NUM_CHANNELS]; // 0x07-0x... ? (address step 2) 52 | } hbwconfig; 53 | 54 | 55 | // create channel object for the switches 56 | HBWSwitchAdvanced* switches[NUM_CHANNELS]; 57 | 58 | 59 | class HBSwDevice : public HBWDevice { 60 | public: 61 | HBSwDevice(uint8_t _devicetype, uint8_t _hardware_version, uint16_t _firmware_version, 62 | Stream* _rs485, uint8_t _txen, 63 | uint8_t _configSize, void* _config, 64 | uint8_t _numChannels, HBWChannel** _channels, 65 | Stream* _debugstream, HBWLinkSender* linksender = NULL, HBWLinkReceiver* linkreceiver = NULL) : 66 | HBWDevice(_devicetype, _hardware_version, _firmware_version, 67 | _rs485, _txen, _configSize, _config, _numChannels, ((HBWChannel**)(_channels)), 68 | _debugstream, linksender, linkreceiver) { 69 | }; 70 | virtual void afterReadConfig(); 71 | }; 72 | 73 | // device specific defaults 74 | void HBSwDevice::afterReadConfig() { 75 | if(hbwconfig.logging_time == 0xFF) hbwconfig.logging_time = 50; 76 | }; 77 | 78 | 79 | HBSwDevice* device = NULL; 80 | 81 | 82 | void setup() 83 | { 84 | #ifdef USE_HARDWARE_SERIAL 85 | Serial.begin(19200, SERIAL_8E1); 86 | #else 87 | Serial.begin(115200); // Serial->USB for debug 88 | rs485.begin(); // RS485 via SoftwareSerial, uses 19200 baud! 89 | #endif 90 | 91 | // create channels 92 | static const uint8_t pins[NUM_CHANNELS] = {SWITCH1_PIN, SWITCH2_PIN, SWITCH3_PIN, SWITCH4_PIN, SWITCH5_PIN, SWITCH6_PIN, SWITCH7_PIN, SWITCH8_PIN}; 93 | 94 | // assing switches (relay) pins to channels 95 | for(uint8_t i = 0; i < NUM_CHANNELS; i++) { 96 | switches[i] = new HBWSwitchAdvanced(pins[i], &(hbwconfig.switchCfg[i])); 97 | } 98 | 99 | device = new HBSwDevice(HMW_DEVICETYPE, HARDWARE_VERSION, FIRMWARE_VERSION, 100 | #ifdef USE_HARDWARE_SERIAL 101 | &Serial, 102 | #else 103 | &rs485, 104 | #endif 105 | RS485_TXEN, sizeof(hbwconfig), &hbwconfig, 106 | NUM_CHANNELS, (HBWChannel**)switches, 107 | #ifdef USE_HARDWARE_SERIAL // set _debugstream to NULL 108 | NULL, 109 | #else 110 | &Serial, 111 | #endif 112 | NULL, new HBWLinkSwitchAdvanced()); 113 | 114 | device->setConfigPins(BUTTON, LED); // 8 and 13 is the default 115 | 116 | 117 | #ifndef USE_HARDWARE_SERIAL 118 | hbwdebug(F("B: 2A ")); 119 | hbwdebug(freeRam()); 120 | hbwdebug(F("\n")); 121 | #endif 122 | } 123 | 124 | 125 | void loop() 126 | { 127 | device->loop(); 128 | POWERSAVE(); // go sleep a bit 129 | }; 130 | -------------------------------------------------------------------------------- /HBW-LC-Sw-8_AdvancedPeering/HBW-LC-Sw-8_AdvancedPeering_config_example.h: -------------------------------------------------------------------------------- 1 | /* Default / example configuation file. When using custom device config (pinout, EEPROM, etc.) or controller, 2 | * copy this file and adjust it. This would also avoid to owerwrite it with new versions from GitHub. */ 3 | 4 | // Arduino NANO / ATMega 328p config - RS485 bus is attached to SoftwareSerial by default, UART0 is used for serial debug. 5 | 6 | EEPROMClass* EepromPtr = &EEPROM; // use internal EEPROM 7 | 8 | // #define USE_HARDWARE_SERIAL // use hardware serial (USART) for final device - this disables debug output 9 | /* Undefine "HBW_DEBUG" in 'HBWired.h' to remove unneeded code. "HBW_DEBUG" also works as master switch, 10 | * as hbwdebug() or hbwdebughex() used in channels will point to empty functions. */ 11 | 12 | 13 | // Pins 14 | #ifdef USE_HARDWARE_SERIAL 15 | #define RS485_TXEN 2 // Transmit-Enable 16 | #define BUTTON A6 // Button fuer Factory-Reset etc. 17 | #define LED LED_BUILTIN // Signal-LED 18 | 19 | #define SWITCH1_PIN A4 // Ausgangpins fuer die Relais 20 | #define SWITCH2_PIN A2 21 | #define SWITCH3_PIN A0 22 | #define SWITCH4_PIN 10 23 | #define SWITCH5_PIN A1 24 | #define SWITCH6_PIN 9 25 | #define SWITCH7_PIN A3 26 | #define SWITCH8_PIN 5 27 | 28 | #else 29 | #define RS485_RXD 4 30 | #define RS485_TXD 2 31 | #define RS485_TXEN 3 // Transmit-Enable 32 | #define BUTTON 8 // Button fuer Factory-Reset etc. 33 | #define LED LED_BUILTIN // Signal-LED 34 | 35 | #define SWITCH1_PIN A0 // Ausgangpins fuer die Relais 36 | #define SWITCH2_PIN A1 37 | #define SWITCH3_PIN A2 38 | #define SWITCH4_PIN A3 39 | #define SWITCH5_PIN A4 40 | #define SWITCH6_PIN A5 41 | #define SWITCH7_PIN 10 42 | #define SWITCH8_PIN 11 43 | 44 | #include 45 | #include 46 | HBWSoftwareSerial rs485(RS485_RXD, RS485_TXD); // RX, TX 47 | #endif 48 | 49 | -------------------------------------------------------------------------------- /HBW-LC-Sw-8_AdvancedPeering/readme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThorstenPferdekaemper/HBWired/27cbac299529a660c791c42f2cece74439513561/HBW-LC-Sw-8_AdvancedPeering/readme.txt -------------------------------------------------------------------------------- /HBW-SC-10-Dim-6/HBW-SC-10-Dim-6_config_example.h: -------------------------------------------------------------------------------- 1 | /* Default / example configuation file. When using custom device config (pinout, EEPROM, etc.) or controller, 2 | * copy this file and adjust it. This would also avoid to owerwrite it with new versions from GitHub. */ 3 | 4 | // Arduino NANO / ATMega 328p config - RS485 bus is attached to SoftwareSerial by default, UART0 is used for serial debug. 5 | 6 | EEPROMClass* EepromPtr = &EEPROM; // use internal EEPROM 7 | 8 | // #define USE_HARDWARE_SERIAL // use hardware serial (USART) for final device - this disables debug output 9 | /* Undefine "HBW_DEBUG" in 'HBWired.h' to remove unneeded code. "HBW_DEBUG" also works as master switch, 10 | * as hbwdebug() or hbwdebughex() used in channels will point to empty functions. */ 11 | 12 | #include "SetupTimer_328p.h" 13 | 14 | inline void SetupHardware() 15 | { 16 | setupPwmTimer1(); 17 | setupPwmTimer2(); 18 | }; 19 | 20 | // Pins 21 | #ifdef USE_HARDWARE_SERIAL 22 | #define RS485_TXEN 2 // Transmit-Enable 23 | #define BUTTON A6 // Button fuer Factory-Reset etc. 24 | #define LED LED_BUILTIN // Signal-LED 25 | 26 | #define PWM1 9 // PWM out (controlled by timer1) 27 | #define PWM2_DAC 5 // PWM out (controlled by timer0) 28 | #define PWM3_DAC 10 // PWM out (controlled by timer1) 29 | #define PWM4 6 // PWM out (controlled by timer0) 30 | #define PWM5 11 // PWM out (controlled by timer2) 31 | #define PWM6 3 // PWM out (controlled by timer2) 32 | 33 | #define IO1 A3 34 | #define IO2 A2 35 | #define IO3 A1 36 | #define IO4 A0 37 | #define IO5 4 38 | #define IO6 7 39 | #define IO7 8 40 | #define IO8 12 41 | #define IO9 A4 42 | #define IO10 A5 43 | 44 | #else 45 | #define RS485_RXD 4 46 | #define RS485_TXD 2 47 | #define RS485_TXEN 3 // Transmit-Enable 48 | #define BUTTON 8 // Button fuer Factory-Reset etc. 49 | #define LED LED_BUILTIN // Signal-LED 50 | 51 | #define PWM1 9 52 | #define PWM2_DAC 5 53 | #define PWM3_DAC 10 54 | #define PWM4 6 55 | #define PWM5 11 56 | #define PWM6 NOT_A_PIN // dummy pin to fill the array elements 57 | 58 | #define IO1 7 59 | #define IO2 A5 60 | #define IO3 12 61 | #define IO4 A0 62 | #define IO5 A1 63 | #define IO6 A2 64 | #define IO7 A3 65 | #define IO8 A4 66 | #define IO9 NOT_A_PIN // dummy pin to fill the array elements 67 | #define IO10 NOT_A_PIN // dummy pin to fill the array elements 68 | 69 | #include "FreeRam.h" 70 | #include 71 | HBWSoftwareSerial rs485(RS485_RXD, RS485_TXD); // RX, TX 72 | #endif //USE_HARDWARE_SERIAL 73 | 74 | -------------------------------------------------------------------------------- /HBW-SC-10-Dim-6/HBWDimmerVirtual.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * HBWDimmerVirtual.cpp 3 | * 4 | * Created (www.loetmeister.de): 10.05.2021 5 | * 6 | */ 7 | 8 | #include "HBWDimmerVirtual.h" 9 | #include 10 | 11 | // Class HBWDimmerVirtual 12 | HBWDimmerVirtual::HBWDimmerVirtual(HBWChannel* _dimChan, hbw_config_dim_virt* _config) : 13 | dimChan(_dimChan), 14 | config(_config) 15 | { 16 | level = 255; // inactive by default 17 | } 18 | 19 | 20 | void HBWDimmerVirtual::set(HBWDevice* device, uint8_t length, uint8_t const * const data) 21 | { 22 | if (length == 1 && *(data) <= 200) { // reference level set by FHEM/CCU; TODO: allow level > 200 to disable again?? 23 | level = *(data); 24 | } 25 | else if (length == HBWDimmerAdvanced::NUM_PEER_PARAMS +2) 26 | { 27 | hbwdebug(F("vDim, onLvl:"));hbwdebug(data[D_POS_onLevel]); 28 | // create new (writable) array 29 | // uint8_t dataNew[HBWDimmerAdvanced::NUM_PEER_PARAMS +2]; 30 | // memcpy(dataNew, data, HBWDimmerAdvanced::NUM_PEER_PARAMS +2); 31 | // dataNew[D_POS_onLevel] = handleLogic(dataNew[D_POS_onLevel]);//, level); 32 | // dimChan->set(device, length, dataNew); 33 | 34 | uint8_t new_onLevel = handleLogic(data[D_POS_onLevel]); 35 | memcpy((uint8_t*)&(data[D_POS_onLevel]), &new_onLevel, 1); // overwrite onLevel byte in data[] array 36 | hbwdebug(F(" new"));hbwdebug(data[D_POS_onLevel]);hbwdebug(F("\n")); 37 | dimChan->set(device, length, data); 38 | } 39 | }; 40 | 41 | 42 | /* standard public function - returns length of data array. Data array contains current channel reading */ 43 | uint8_t HBWDimmerVirtual::get(uint8_t* data) 44 | { 45 | *data++ = level; 46 | *data = (level != 255) ? 48 : 0; // level of 255 is "logic inactive" state 47 | 48 | return 2; 49 | }; 50 | 51 | uint8_t HBWDimmerVirtual::handleLogic(uint8_t levelPeer) 52 | { 53 | if (level > 200) return levelPeer; // exit if we have no value for proper comparison. level have to be set first 54 | 55 | if (levelPeer > 200) levelPeer = 200; // this would ignore onLevel = 201 (old_onlevel)... cannot handle it from here anyway.. 56 | 57 | switch(config->logic) 58 | { 59 | case LOGIC_INACTIVE: 60 | // skip 61 | break; 62 | 63 | // case LOGIC_ORINVERS: 64 | // level = 200 - level; //? 65 | // levelPeer = 200 - levelPeer; 66 | // return (level > levelPeer ? level : levelPeer); 67 | 68 | case LOGIC_OR: // use larger value 69 | if (level > levelPeer) return level; 70 | break; 71 | 72 | // case LOGIC_ANDINVERS: //? 73 | // levelPeer = 200 - levelPeer; 74 | // return level < levelPeer ? level : levelPeer; 75 | 76 | case LOGIC_AND: // use smaller value 77 | if (level < levelPeer) return level; 78 | break; 79 | 80 | case LOGIC_XOR: // one level has to be 0 81 | return (level == 0 ? levelPeer : (levelPeer == 0 ? level : 0)); 82 | break; 83 | 84 | case LOGIC_NOR: // use larger value & invert 85 | return (200 - ((level > levelPeer) ? level : levelPeer)); 86 | break; 87 | 88 | case LOGIC_NAND: // use smaller value & invert 89 | return (200 - ((level < levelPeer) ? level : levelPeer)); 90 | break; 91 | 92 | case LOGIC_PLUS: // addition (max 100%) 93 | return ((uint16_t)(levelPeer + level) > 200) ? 200 : (levelPeer + level); 94 | break; 95 | 96 | case LOGIC_MINUS: // substraction (min 0%) 97 | return levelPeer - ((levelPeer > level) ? level : levelPeer); 98 | break; 99 | default: break; 100 | } 101 | return levelPeer; 102 | }; 103 | 104 | -------------------------------------------------------------------------------- /HBW-SC-10-Dim-6/HBWDimmerVirtual.h: -------------------------------------------------------------------------------- 1 | /* 2 | * HBWDimmerVirtual.h 3 | * 4 | * HBWDimmerVirtual should be used with a dimmer channel (HBWDimmerAdvanced & HBWLinkDimmerAdvanced). 5 | * It allows to influence the on_level of the physical dimmer channel, by combining the level set 6 | * from peering with the level of its own channel with various logic. 7 | * Not all logic combinations are implemneted (may also not useful for a single virtual channel). 8 | * 9 | * Flow: key ->(peering)-> dimmer_virtual ->(levels + logic)-> dimmer channel 10 | * 11 | * TODO: A virtual dimmer channel should actually have a full state machine... 12 | */ 13 | 14 | #ifndef HBWDimmerVirtual_h 15 | #define HBWDimmerVirtual_h 16 | 17 | #include 18 | #include "HBWired.h" 19 | 20 | 21 | // #define DEBUG_OUTPUT 22 | 23 | 24 | // config of each virtual dimmer channel, address step 1 25 | struct hbw_config_dim_virt { 26 | uint8_t logic:5; // LOGIC_INACTIVE, LOGIC_OR, ... 27 | uint8_t :3; // not used 28 | }; 29 | 30 | 31 | // Class HBWDimmerVirtual 32 | class HBWDimmerVirtual : public HBWChannel { 33 | public: 34 | HBWDimmerVirtual(HBWChannel* _dimChan, hbw_config_dim_virt* _config); 35 | // virtual void loop(HBWDevice*, uint8_t channel); 36 | virtual void set(HBWDevice*, uint8_t length, uint8_t const * const data); 37 | virtual uint8_t get(uint8_t* data); 38 | 39 | enum logic { 40 | LOGIC_INACTIVE = 0, 41 | LOGIC_OR, 42 | LOGIC_AND, 43 | LOGIC_XOR, 44 | LOGIC_NOR, 45 | LOGIC_NAND, 46 | LOGIC_ORINVERS, 47 | LOGIC_ANDINVERS, 48 | LOGIC_PLUS, 49 | LOGIC_MINUS, 50 | LOGIC_MULTI, 51 | LOGIC_PLUSINVERS, 52 | LOGIC_MINUSINVERS, 53 | LOGIC_MULTIINVERS, 54 | LOGIC_INVERSPLUS, 55 | LOGIC_INVERSMINUS, 56 | LOGIC_INVERSMULTI 57 | }; 58 | 59 | private: 60 | HBWChannel* dimChan; // mapped dimmer channel (or another virtual dimmer?) 61 | hbw_config_dim_virt* config; 62 | //uint8_t onLevel; // level from peering - need to be stored? 63 | uint8_t level; // level (0...100%) set for the channel to use in LOGIC condition 64 | 65 | uint8_t handleLogic(uint8_t levelPeer); 66 | }; 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /HBW-SC-10-Dim-6/HBWKeyVirtual.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * HBWKeyVirtual.cpp 3 | * 4 | * Updated (www.loetmeister.de): 9.08.2020 5 | * 6 | */ 7 | 8 | #include "HBWKeyVirtual.h" 9 | 10 | // Class HBWKeyVirtual 11 | HBWKeyVirtual::HBWKeyVirtual(uint8_t _mappedChan, hbw_config_key_virt* _config) : 12 | mappedChan(_mappedChan), 13 | config(_config) 14 | { 15 | keyPressNum = 0; 16 | keyPressedMillis = 0; 17 | updateDone = false; 18 | } 19 | 20 | 21 | // sends a short KeyEvent for mappedChan state not 0 and long KeyEvent for state equals 0 22 | void HBWKeyVirtual::loop(HBWDevice* device, uint8_t channel) { 23 | 24 | if (config->input_locked) return; // locked by default 25 | 26 | if (millis() - keyPressedMillis < POLLING_WAIT_TIME) return; 27 | 28 | uint8_t value; 29 | device->get(mappedChan, &value); // check length? switch or dimmer use only 1 byte for the level. 2nd byte are state flags 30 | 31 | value = (value == 0) ? false : true; 32 | sendLong = (value == config->n_inverted) ? false : true; 33 | 34 | if (!config->n_update_on_start && !updateDone) { 35 | lastSentLong = !sendLong; // force to send key event on device start (disabled by default) 36 | updateDone = true; 37 | } 38 | 39 | if (lastSentLong != sendLong) { 40 | // send short key event immediately, delay long key event (off delay) 41 | if (millis() - keyPressedMillis > OFF_DELAY_TIME || !sendLong) { 42 | 43 | #ifdef DEBUG_OUTPUT 44 | hbwdebug(F("VKey_ch:")); 45 | hbwdebug(mappedChan); 46 | if (sendLong) hbwdebug(F(" long")); else hbwdebug(F(" short")); 47 | hbwdebug(F("\n")); 48 | #endif 49 | 50 | if (device->sendKeyEvent(channel, keyPressNum, sendLong) != HBWDevice::BUS_BUSY) { // && retryCounter 51 | keyPressNum++; 52 | lastSentLong = sendLong; 53 | } 54 | // TODO: add counter for retry handling - e.g. give up after 3 tries? 55 | } 56 | } 57 | else { 58 | keyPressedMillis = millis(); 59 | } 60 | }; 61 | -------------------------------------------------------------------------------- /HBW-SC-10-Dim-6/HBWKeyVirtual.h: -------------------------------------------------------------------------------- 1 | /* 2 | * HBWKeyVirtual.h 3 | * 4 | * HBWKeyVirtual can be used to read actor channels, like switch or dimmer 5 | * It will send a short KeyEvent, if the attached channel (mappedChan) state not 0 6 | * and long KeyEvent for state equals 0. 7 | * HBWKeyVirtual can be peered like any normal key channel (using HBWLinkKey.h) 8 | */ 9 | // TODO: link this by dimmer channel, to have a trigger and avoid polling? (e.g. HBWDimmerAdvanced(uint8_t _pin, hbw_config_dim* _config, HBWKeyVirtual* _vKey)) 10 | 11 | #ifndef HBWKeyVirtual_h 12 | #define HBWKeyVirtual_h 13 | 14 | #include 15 | #include "HBWired.h" 16 | 17 | 18 | // #define DEBUG_OUTPUT 19 | 20 | 21 | // config of each virtual key channel, address step 1 22 | struct hbw_config_key_virt { 23 | uint8_t input_locked:1; // 0x07:0 default 1=LOCKED, 0=UNLOCKED 24 | uint8_t n_inverted:1; // 0x07:1 0=inverted, 1=not inverted 25 | uint8_t n_update_on_start:1; // 0x07:2 0 = send key event on device start, 1 = don't 26 | uint8_t :5; // 0x07:3-7 27 | //TODO: use 3 bit for OFF_DELAY_TIME? (0..7 seconds?) 28 | }; 29 | 30 | 31 | // Class HBWKeyVirtual 32 | class HBWKeyVirtual : public HBWChannel { 33 | public: 34 | HBWKeyVirtual(uint8_t _mappedChan, hbw_config_key_virt* _config); 35 | virtual void loop(HBWDevice*, uint8_t channel); 36 | 37 | 38 | private: 39 | uint8_t mappedChan; // mapped channel number 40 | hbw_config_key_virt* config; 41 | 42 | uint8_t keyPressNum; 43 | uint32_t keyPressedMillis; // Zeit, zu der die Taste gedrueckt wurde (fuer's Entprellen) 44 | boolean sendLong; // Zu sendender "Tastendruck" long (=true) oder short 45 | boolean lastSentLong; // Zuletzt gesender "Tastendruck" long oder short 46 | boolean updateDone; 47 | 48 | static const uint16_t OFF_DELAY_TIME = 2600; // ms (should be multiple of POLLING_WAIT_TIME) 49 | static const uint16_t POLLING_WAIT_TIME = 325; // ms, get linked channel state not faster than this 50 | }; 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /HBW-SC-10-Dim-6/SetupTimer_328p.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Setup PWM, to have 4 channels with 122Hz output, 3 | * to interface with Eltako LUD12-230V (ideally 100HZ @ min. 10V) 4 | * 5 | * http://loetmeister.de/Elektronik/homematic/ 6 | * 7 | */ 8 | 9 | #ifndef SetupTimer_328p_h 10 | #define SetupTimer_328p_h 11 | 12 | 13 | //change from fast-PWM to phase-correct PWM 14 | // (This is the timer0 controlled PWM module. Do not change prescaler, it would impact millis() & delay() functions.) 15 | //TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM00); 16 | // TCCR0A = B00000001; // phase-correct PWM @490Hz 17 | // TODO: fixme - not working! millis() is running two times slower when not in fast-PWM! - interrupt 'issue' 18 | 19 | 20 | inline void setupPwmTimer1(void) { 21 | // Setup Timer1 for 122.5Hz PWM 22 | TCCR1A = 0; // undo the configuration done by... 23 | TCCR1B = 0; // ...the Arduino core library 24 | TCNT1 = 0; // reset timer 25 | TCCR1A = _BV(COM1A1) // non-inverted PWM on ch. A 26 | | _BV(COM1B1) // same on ch. B 27 | | _BV(WGM11); // mode 10: ph. correct PWM, TOP = ICR1 28 | TCCR1B = _BV(WGM13) // ditto 29 | //| _BV(WGM12) // fast PWM: mode 14, TOP = ICR1 30 | | _BV(CS12); // prescaler = 256 31 | //ICR1 = 312; // 100Hz //TODO: ? create custom analogWrite() to consider ICR1 as upper limit: e.g. OCR1A = map(val,0,255,0,ICR1); 32 | ICR1 = 255; // 122.5Hz - this work with default analogWrite() function (which is setting a level between 0 and 255) 33 | } 34 | 35 | 36 | inline void setupPwmTimer2(void) { 37 | // Timer 2 @122.5Hz 38 | TCNT2 = 0; 39 | TCCR2A = B10100001; // mode 1: ph. correct PWM, TOP = OxFF 40 | TCCR2B = B00000110; // prescaler = 256 41 | } 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /HBW-SC-10-Dim-6/readme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThorstenPferdekaemper/HBWired/27cbac299529a660c791c42f2cece74439513561/HBW-SC-10-Dim-6/readme.txt -------------------------------------------------------------------------------- /HBW-Sen-DB-4/HBW-Sen-DB-4_config_example.h: -------------------------------------------------------------------------------- 1 | /* Default / example configuation file. When using custom device config (pinout, EEPROM, etc.) or controller, 2 | * copy this file and adjust it. This would also avoid to owerwrite it with new versions from GitHub. */ 3 | 4 | // Arduino NANO / ATMega 328p config - RS485 bus is attached to SoftwareSerial by default, UART0 is used for serial debug. 5 | 6 | EEPROMClass* EepromPtr = &EEPROM; // use internal EEPROM 7 | 8 | // #define USE_HARDWARE_SERIAL // use hardware serial (USART) for final device - this disables debug output 9 | /* Undefine "HBW_DEBUG" in 'HBWired.h' to remove unneeded code. "HBW_DEBUG" also works as master switch, 10 | * as hbwdebug() or hbwdebughex() used in channels will point to empty functions. */ 11 | 12 | #ifdef USE_HARDWARE_SERIAL 13 | #define RS485_TXEN 2 // Transmit-Enable 14 | #define BUTTON A6 // Button fuer Factory-Reset etc. 15 | #define LED LED_BUILTIN // Signal-LED 16 | 17 | #define BUTTON_1 8 18 | #define BUTTON_2 7 19 | #define BUTTON_3 4 20 | #define BUTTON_4 A1 21 | 22 | #define BUZZER 11 // buzzer for key press feedback (timer2) 23 | #define BACKLIGHT_PWM 9 // timer1 (pin 9 & 10) 24 | #define LDR_PIN A0 25 | // #define BLOCKED_TWI_SDA A4 // used by I²C - SDA 26 | // #define BLOCKED_TWI_SCL A5 // used by I²C - SCL 27 | 28 | #else 29 | #define RS485_RXD 4 30 | #define RS485_TXD 2 31 | #define RS485_TXEN 3 // Transmit-Enable 32 | #define BUTTON 8 // Button fuer Factory-Reset etc. 33 | #define LED LED_BUILTIN // Signal-LED 34 | 35 | #define BUTTON_1 A0 36 | #define BUTTON_2 A1 37 | #define BUTTON_3 A2 38 | #define BUTTON_4 A3 39 | 40 | #define BUZZER 11 // buzzer for key press feedback (tone() timer prio: timer2, 1, 0) 41 | // 11, 3 (controlled by timer2), timer0 (pin 5 & 6), timer1 (pin 9 & 10) 42 | #define BACKLIGHT_PWM 9 43 | #define LDR_PIN A7 44 | // #define BLOCKED_TWI_SDA A4 // used by I²C - SDA 45 | // #define BLOCKED_TWI_SCL A5 // used by I²C - SCL 46 | 47 | #include "FreeRam.h" 48 | #include "HBWSoftwareSerial.h" 49 | HBWSoftwareSerial rs485(RS485_RXD, RS485_TXD); // RX, TX 50 | #endif //USE_HARDWARE_SERIAL 51 | 52 | 53 | -------------------------------------------------------------------------------- /HBW-Sen-DB-4/HBWKeyDoorbell.h: -------------------------------------------------------------------------------- 1 | /* 2 | * HBWKeyDoorbell.h 3 | * 4 | * Created (www.loetmeister.de): 25.01.2020 5 | * 6 | * build for doorbell pushbuttons 7 | * allows to block for a specific time, if someone keeps ringing 8 | */ 9 | 10 | #ifndef HBWKeyDoorbell_h 11 | #define HBWKeyDoorbell_h 12 | 13 | #include 14 | #include "HBWired.h" 15 | // To play buzzer tones 16 | #include "pitches.h" 17 | 18 | // #define DEBUG_OUTPUT 19 | 20 | 21 | // config, address step 5 22 | struct hbw_config_key_doorbell { 23 | uint8_t n_input_locked:1; // +0.0 0=LOCKED, 1=UNLOCKED 24 | uint8_t n_inverted:1; // +0.1 0=inverted, 1=not inverted 25 | uint8_t pullup:1; // +0.2 // TODO: needed....? 26 | uint8_t repeat_long_press:1; // allow long press KeyEvent for depressed key (press and hold) - send again after suppress_time passed 27 | // uint8_t :3; // 0x07:5-7 28 | uint8_t long_press_time; // +1.0 29 | // key blocking: first key press will always be send. Next one after 'suppress_num' count was reached or no key was pressed during 'suppress_time' 30 | // long_press will be repeated every 'suppress_time' (unless disabled by repeat_long_press) 31 | uint8_t suppress_num:4; // +2.0 amount of presses that will be suppressed (0-14) 32 | uint8_t :4; 33 | uint8_t suppress_time:4; // +3.0 blocking time for repeated key presses (0-14 sec) 34 | uint8_t buzzer:3; // +3.4 buzzer config (TODO: melody1, melody2, melody3, melody4), disabled=0, 7=default melody 35 | uint8_t fillup:1; 36 | uint8_t dummy; 37 | }; 38 | 39 | #define NUM_NOTES 3 40 | // note=0 creates silence. length=1000 skips the note (dealy 1.3ms), length=0 stops the melody (starting with 0 will disable the whole melody!) 41 | // fields: melody[melody 'pair'][fail|ok][note|note length][note] 42 | PROGMEM const int melody[][2][2][NUM_NOTES] = { 43 | { { {NOTE_A3, NOTE_C3, 0}, {8, 4, 0} }, { {0, NOTE_B5, NOTE_E6}, {1000, 16, 8} } }, // default melody 44 | { { {NOTE_A3, NOTE_C3, 0}, {8, 4, 0} }, { {NOTE_G4, NOTE_F4, NOTE_D5}, {16, 8, 0} } }, // melody1 45 | { { {NOTE_A3, NOTE_C3, 0}, {8, 4, 0} }, { {NOTE_B5, NOTE_E6, 0}, {16, 8, 0} } } // melody2 dummy 46 | }; 47 | 48 | 49 | // Class HBWKeyDoorbell 50 | class HBWKeyDoorbell : public HBWChannel { 51 | public: 52 | HBWKeyDoorbell(uint8_t _pin, hbw_config_key_doorbell* _config, uint8_t _pinBuzzer = NOT_A_PIN, bool _activeHigh = false); 53 | virtual void loop(HBWDevice*, uint8_t channel); 54 | virtual void afterReadConfig(); 55 | 56 | 57 | private: 58 | hbw_config_key_doorbell* config; 59 | uint8_t pin; // input pin 60 | uint32_t keyPressedMillis; // Zeit, zu der die Taste gedrueckt wurde (fuer's Entprellen) 61 | uint32_t lastSentLong; // Zeit, zu der das letzte Mal longPress gesendet wurde 62 | uint8_t keyPressNum; 63 | uint8_t repeatCounter; 64 | uint32_t lastKeyPressedMillis; // last press of any key 65 | bool activeHigh; // activeHigh=true -> input active high, else active low 66 | 67 | static const uint32_t KEY_DEBOUNCE_TIME = 85; // ms 68 | 69 | enum buzzerAction { 70 | BLOCKED = 0, // must match with melody array index for the 'fail/ok' field (0/1) 71 | SUCCESS, 72 | PLAY 73 | }; 74 | enum { 75 | NOTE = 0, // must match with melody array index for the 'note/note length' field (0/1) 76 | NOTE_LEN 77 | }; 78 | uint8_t pinBuzzer; // pin for the buzzer - if used 79 | void buzzer(uint8_t _action, bool _forceChange = false); 80 | 81 | static const uint8_t MAX_MELODY_CONFIG = 7; // need to match with device XML 82 | }; 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /HBW-Sen-DB-4/pitches.h: -------------------------------------------------------------------------------- 1 | /************************************************* 2 | Public Constants 3 | *************************************************/ 4 | 5 | #define NOTE_B0 31 6 | #define NOTE_C1 33 7 | #define NOTE_CS1 35 8 | #define NOTE_D1 37 9 | #define NOTE_DS1 39 10 | #define NOTE_E1 41 11 | #define NOTE_F1 44 12 | #define NOTE_FS1 46 13 | #define NOTE_G1 49 14 | #define NOTE_GS1 52 15 | #define NOTE_A1 55 16 | #define NOTE_AS1 58 17 | #define NOTE_B1 62 18 | #define NOTE_C2 65 19 | #define NOTE_CS2 69 20 | #define NOTE_D2 73 21 | #define NOTE_DS2 78 22 | #define NOTE_E2 82 23 | #define NOTE_F2 87 24 | #define NOTE_FS2 93 25 | #define NOTE_G2 98 26 | #define NOTE_GS2 104 27 | #define NOTE_A2 110 28 | #define NOTE_AS2 117 29 | #define NOTE_B2 123 30 | #define NOTE_C3 131 31 | #define NOTE_CS3 139 32 | #define NOTE_D3 147 33 | #define NOTE_DS3 156 34 | #define NOTE_E3 165 35 | #define NOTE_F3 175 36 | #define NOTE_FS3 185 37 | #define NOTE_G3 196 38 | #define NOTE_GS3 208 39 | #define NOTE_A3 220 40 | #define NOTE_AS3 233 41 | #define NOTE_B3 247 42 | #define NOTE_C4 262 43 | #define NOTE_CS4 277 44 | #define NOTE_D4 294 45 | #define NOTE_DS4 311 46 | #define NOTE_E4 330 47 | #define NOTE_F4 349 48 | #define NOTE_FS4 370 49 | #define NOTE_G4 392 50 | #define NOTE_GS4 415 51 | #define NOTE_A4 440 52 | #define NOTE_AS4 466 53 | #define NOTE_B4 494 54 | #define NOTE_C5 523 55 | #define NOTE_CS5 554 56 | #define NOTE_D5 587 57 | #define NOTE_DS5 622 58 | #define NOTE_E5 659 59 | #define NOTE_F5 698 60 | #define NOTE_FS5 740 61 | #define NOTE_G5 784 62 | #define NOTE_GS5 831 63 | #define NOTE_A5 880 64 | #define NOTE_AS5 932 65 | #define NOTE_B5 988 66 | #define NOTE_C6 1047 67 | #define NOTE_CS6 1109 68 | #define NOTE_D6 1175 69 | #define NOTE_DS6 1245 70 | #define NOTE_E6 1319 71 | #define NOTE_F6 1397 72 | #define NOTE_FS6 1480 73 | #define NOTE_G6 1568 74 | #define NOTE_GS6 1661 75 | #define NOTE_A6 1760 76 | #define NOTE_AS6 1865 77 | #define NOTE_B6 1976 78 | #define NOTE_C7 2093 79 | #define NOTE_CS7 2217 80 | #define NOTE_D7 2349 81 | #define NOTE_DS7 2489 82 | #define NOTE_E7 2637 83 | #define NOTE_F7 2794 84 | #define NOTE_FS7 2960 85 | #define NOTE_G7 3136 86 | #define NOTE_GS7 3322 87 | #define NOTE_A7 3520 88 | #define NOTE_AS7 3729 89 | #define NOTE_B7 3951 90 | #define NOTE_C8 4186 91 | #define NOTE_CS8 4435 92 | #define NOTE_D8 4699 93 | #define NOTE_DS8 4978 94 | -------------------------------------------------------------------------------- /HBW-Sen-DB-4/readme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThorstenPferdekaemper/HBWired/27cbac299529a660c791c42f2cece74439513561/HBW-Sen-DB-4/readme.txt -------------------------------------------------------------------------------- /HBW-Sen-EP/HBW-Sen-EP.ino: -------------------------------------------------------------------------------- 1 | //******************************************************************* 2 | // 3 | // HBW-Sen-EP, RS485 8-channel Puls Counter / S0 interface 4 | // 5 | // Homematic Wired Hombrew Hardware 6 | // Arduino NANO als Homematic-Device 7 | // 8 | // HBW-Sen-EP zum Zählen von elektrischen Pulsen (z.B. S0-Schnittstelle) 9 | // 10 | // http://loetmeister.de/Elektronik/homematic/index.htm#modules 11 | // 12 | //******************************************************************* 13 | // Changes 14 | // v0.01 15 | // - initial version 16 | // v0.02 17 | // - rework of channel loop - reading input 18 | // - removed POLLING_TIME config (replaced by fixed debounce time - DEBOUNCE_DELAY set in HBWSenEP.h) 19 | 20 | 21 | #define HARDWARE_VERSION 0x01 22 | #define FIRMWARE_VERSION 0x0002 23 | #define HMW_DEVICETYPE 0x84 //device ID (make sure to import hbw-sen-ep.xml into FHEM) 24 | 25 | #define NUMBER_OF_SEN_CHAN 8 // input channels 26 | 27 | 28 | // HB Wired protocol and modules 29 | #include 30 | #include 31 | #include 32 | 33 | 34 | // Pins and hardware config 35 | #include "HBW-Sen-EP_config_example.h" // When using custom device pinout or controller, copy this file and include it instead 36 | 37 | 38 | #define NUMBER_OF_CHAN NUMBER_OF_SEN_CHAN 39 | 40 | 41 | struct hbw_config { 42 | uint8_t logging_time; // 0x01 43 | uint32_t central_address; // 0x02 - 0x05 44 | uint8_t direct_link_deactivate:1; // 0x06:0 45 | uint8_t :7; // 0x06:1-7 46 | hbw_config_sen_ep SenEpCfg[NUMBER_OF_SEN_CHAN]; // 0x07 - 0x..(address step 9) 47 | } hbwconfig; 48 | 49 | 50 | HBWChannel* channels[NUMBER_OF_CHAN]; // total number of channels for the device 51 | HBWDevice* device = NULL; 52 | 53 | 54 | void setup() 55 | { 56 | // create channels 57 | static const uint8_t SenPin[NUMBER_OF_SEN_CHAN] = {Sen1, Sen2, Sen3, Sen4, Sen5, Sen6, Sen7, Sen8}; // assing pins 58 | 59 | for(uint8_t i = 0; i < NUMBER_OF_SEN_CHAN; i++) { 60 | channels[i] = new HBWSenEP(SenPin[i], &(hbwconfig.SenEpCfg[i])); 61 | } 62 | 63 | 64 | #ifdef USE_HARDWARE_SERIAL // RS485 via UART Serial, no debug (_debugstream is NULL) 65 | Serial.begin(19200, SERIAL_8E1); 66 | 67 | device = new HBWDevice(HMW_DEVICETYPE, HARDWARE_VERSION, FIRMWARE_VERSION, 68 | &Serial, RS485_TXEN, sizeof(hbwconfig), &hbwconfig, 69 | NUMBER_OF_CHAN, (HBWChannel**)channels, 70 | NULL, 71 | NULL, NULL); 72 | 73 | device->setConfigPins(BUTTON, LED); // use analog input for 'BUTTON' 74 | 75 | #else 76 | Serial.begin(115200); // Serial->USB for debug 77 | rs485.begin(19200); // RS485 via SoftwareSerial, must use 19200 baud! 78 | 79 | device = new HBWDevice(HMW_DEVICETYPE, HARDWARE_VERSION, FIRMWARE_VERSION, 80 | &rs485, RS485_TXEN, sizeof(hbwconfig), &hbwconfig, 81 | NUMBER_OF_CHAN, (HBWChannel**)channels, 82 | &Serial, 83 | NULL, NULL); 84 | 85 | device->setConfigPins(BUTTON, LED); // 8 (button) and 13 (led) is the default 86 | 87 | hbwdebug(F("B: 2A ")); 88 | hbwdebug(freeRam()); 89 | hbwdebug(F("\n")); 90 | #endif 91 | } 92 | 93 | 94 | void loop() 95 | { 96 | device->loop(); 97 | POWERSAVE(); // go sleep a bit 98 | }; 99 | -------------------------------------------------------------------------------- /HBW-Sen-EP/HBW-Sen-EP_config_example.h: -------------------------------------------------------------------------------- 1 | /* Default / example configuation file. When using custom device config (pinout, EEPROM, etc.) or controller, 2 | * copy this file and adjust it. This would also avoid to owerwrite it with new versions from GitHub. */ 3 | 4 | // Arduino NANO / ATMega 328p config - RS485 bus is attached to SoftwareSerial by default, UART0 is used for serial debug. 5 | 6 | EEPROMClass* EepromPtr = &EEPROM; // use internal EEPROM 7 | 8 | // #define USE_HARDWARE_SERIAL // use hardware serial (USART) for final device - this disables debug output 9 | /* Undefine "HBW_DEBUG" in 'HBWired.h' to remove unneeded code. "HBW_DEBUG" also works as master switch, 10 | * as hbwdebug() or hbwdebughex() used in channels will point to empty functions. */ 11 | 12 | 13 | // Pins 14 | #ifdef USE_HARDWARE_SERIAL 15 | #define RS485_TXEN 2 // Transmit-Enable 16 | #define BUTTON A6 // Button fuer Factory-Reset etc. 17 | #define LED LED_BUILTIN // Signal-LED 18 | 19 | #define Sen1 A0 // digital input 20 | #define Sen2 A1 21 | #define Sen3 A2 22 | #define Sen4 9 23 | #define Sen5 10 24 | #define Sen6 11 25 | #define Sen7 4 26 | #define Sen8 7 27 | 28 | // #define BLOCKED_TWI_SDA SDA //A4 // reserved for I²C 29 | // #define BLOCKED_TWI_SCL SCL //A5 // reserved for I²C 30 | 31 | #else 32 | #define RS485_RXD 4 33 | #define RS485_TXD 2 34 | #define RS485_TXEN 3 // Transmit-Enable 35 | #define BUTTON 8 // Button fuer Factory-Reset etc. 36 | #define LED LED_BUILTIN // Signal-LED 37 | 38 | #define Sen1 A0 // digital input 39 | #define Sen2 A1 40 | #define Sen3 A2 41 | #define Sen4 9//A3 42 | #define Sen5 10//A4 43 | #define Sen6 11//A5 44 | #define Sen7 5 45 | #define Sen8 7 46 | 47 | #include "FreeRam.h" 48 | #include 49 | HBWSoftwareSerial rs485(RS485_RXD, RS485_TXD); // RX, TX 50 | #endif //USE_HARDWARE_SERIAL 51 | 52 | 53 | -------------------------------------------------------------------------------- /HBW-Sen-EP/readme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThorstenPferdekaemper/HBWired/27cbac299529a660c791c42f2cece74439513561/HBW-Sen-EP/readme.txt -------------------------------------------------------------------------------- /HBW-Sen-EP_interrupt-based/HBW-Sen-EP_interrupt-based_config_example.h: -------------------------------------------------------------------------------- 1 | /* Default / example configuation file. When using custom device config (pinout, EEPROM, etc.) or controller, 2 | * copy this file and adjust it. This would also avoid to owerwrite it with new versions from GitHub. */ 3 | 4 | // Arduino NANO / ATMega 328p config - RS485 bus is attached to SoftwareSerial by default, UART0 is used for serial debug. 5 | 6 | EEPROMClass* EepromPtr = &EEPROM; // use internal EEPROM 7 | 8 | #define USE_HARDWARE_SERIAL // use hardware serial (USART) for final device - this disables debug output 9 | /* Undefine "HBW_DEBUG" in 'HBWired.h' to remove unneeded code. "HBW_DEBUG" also works as master switch, 10 | * as hbwdebug() or hbwdebughex() used in channels will point to empty functions. */ 11 | 12 | 13 | //#define USE_LCD // device has build-in display 14 | #define USE_INTERRUPTS_FOR_INPUT_PINS // interrupt support (only possible without SoftwareSerial! Temporarily rename HBWSoftwareSerial.cpp to .cpp_ in HBWired lib, when using Arduino IDE) 15 | 16 | 17 | // Pins 18 | #ifdef USE_LCD 19 | #include "UC121902-TNARX-A.h" 20 | // serial LCD 21 | #define LCD_DI 3 22 | #define LCD_CK 4 23 | #define LCD_CE 5 24 | 25 | #define LCD_BUTTON 12 // Select button for LCD 26 | // #define LCD_LED 6 // extra LED or LCD backlight 27 | 28 | UC121902_TNARX_A::Display LCdisplay(LCD_CE, LCD_CK, LCD_DI); 29 | #endif 30 | 31 | #ifdef USE_HARDWARE_SERIAL 32 | #define RS485_TXEN 2 // Transmit-Enable 33 | #define BUTTON A6 // Button fuer Factory-Reset etc. 34 | 35 | /* digital input supporting port change interrupt 36 | 2 & 3 reserved for ARDUINO_328 */ 37 | #define Sen1 8 38 | #define Sen2 7 39 | #define Sen3 10 40 | #define Sen4 9 41 | #define Sen5 A0 42 | #define Sen6 A1 43 | #define Sen7 A2 44 | #define Sen8 A3 45 | 46 | // #define BLOCKED_TWI_SDA SDA //A4 // reserved for I²C 47 | // #define BLOCKED_TWI_SCL SCL //A5 // reserved for I²C 48 | 49 | #ifdef USE_INTERRUPTS_FOR_INPUT_PINS 50 | #include "HBW-Sen-EP_interrupt.h" 51 | #endif 52 | 53 | #else 54 | #define RS485_RXD 4 55 | #define RS485_TXD 2 56 | #define RS485_TXEN 3 // Transmit-Enable 57 | #define BUTTON 8 // Button fuer Factory-Reset etc. 58 | 59 | #define Sen1 A0 // digital input 60 | #define Sen2 A1 61 | #define Sen3 A2 62 | #define Sen4 9//A3 63 | #define Sen5 10//A4 64 | #define Sen6 11//A5 65 | #define Sen7 5 66 | #define Sen8 7 67 | 68 | #include 69 | #include 70 | HBWSoftwareSerial rs485(RS485_RXD, RS485_TXD); // RX, TX 71 | #endif //USE_HARDWARE_SERIAL 72 | 73 | #define LED LED_BUILTIN // Signal-LED 74 | -------------------------------------------------------------------------------- /HBW-Sen-EP_interrupt-based/HBW-Sen-EP_interrupt.h: -------------------------------------------------------------------------------- 1 | #ifndef HBW_Sen_EP_interrupt_h 2 | #define HBW_Sen_EP_interrupt_h 3 | 4 | 5 | #define EI_ARDUINO_INTERRUPTED_PIN 6 | #include 7 | 8 | 9 | /* arduinoPinState (included from EnableInterrupt.h, by #define EI_ARDUINO_INTERRUPTED_PIN) 10 | The value of the variable is either 0 or some power of two (i.e., 2, 4, 8). 11 | 0 means that the pin changed from high to low signal. 12 | Other than 0 means the pin went from a low signal level to high. 13 | */ 14 | 15 | /* #if defined __AVR_ATmega168__ || defined __AVR_ATmega168A__ || defined __AVR_ATmega168P__ || \ 16 | defined __AVR_ATmega168PA__ || defined __AVR_ATmega328__ || defined __AVR_ATmega328P__ 17 | */ 18 | 19 | #define PINCOUNT(x) pin ##x ##Count 20 | #define PINTIMER(x) pin ##x ##LastMillis 21 | 22 | 23 | // approx. 14 ms debonce (standard S0 puls lenght 30 ms) 24 | // input pulse will increment counter on next pin change interrupt - input was held LOW for debounce duration or more 25 | #define interruptFunction(x) \ 26 | volatile uint16_t PINCOUNT(x); \ 27 | volatile uint32_t PINTIMER(x); \ 28 | void interruptFunction ##x () { \ 29 | if (arduinoPinState != LOW && millis() - PINTIMER(x) >= 14) { PINCOUNT(x)++; } \ 30 | PINTIMER(x) = millis(); \ 31 | } 32 | 33 | 34 | #define setupInterrupt(x) \ 35 | pinMode( x, INPUT_PULLUP); \ 36 | enableInterrupt( x, interruptFunction##x, CHANGE) 37 | 38 | 39 | #define getInterruptCounter(x) \ 40 | PINCOUNT(x) 41 | 42 | 43 | // #else 44 | // #error This sketch supports 328-based Arduinos only at the moment. Possible to add others that support port change interrupts. 45 | // #endif 46 | 47 | 48 | #endif //HBW_Sen_EP_interrupt_h 49 | -------------------------------------------------------------------------------- /HBW-Sen-EP_interrupt-based/hbw-sen-ep.xml: -------------------------------------------------------------------------------- 1 | ../HBW-Sen-EP/hbw-sen-ep.xml -------------------------------------------------------------------------------- /HBW-Sen-EP_interrupt-based/readme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThorstenPferdekaemper/HBWired/27cbac299529a660c791c42f2cece74439513561/HBW-Sen-EP_interrupt-based/readme.txt -------------------------------------------------------------------------------- /HBW-Sen-Key-12/HBW-Sen-Key-12_config_example.h: -------------------------------------------------------------------------------- 1 | /* Default / example configuation file. When using custom device config (pinout, EEPROM, etc.) or controller, 2 | * copy this file and adjust it. This would also avoid to owerwrite it with new versions from GitHub. */ 3 | 4 | // Arduino NANO / ATMega 328p config - RS485 bus is attached to SoftwareSerial by default, UART0 is used for serial debug. 5 | 6 | EEPROMClass* EepromPtr = &EEPROM; // use internal EEPROM 7 | 8 | // #define USE_HARDWARE_SERIAL // use hardware serial (USART) for final device - this disables debug output 9 | /* Undefine "HBW_DEBUG" in 'HBWired.h' to remove unneeded code. "HBW_DEBUG" also works as master switch, 10 | * as hbwdebug() or hbwdebughex() used in channels will point to empty functions. */ 11 | 12 | // Pins 13 | #define RS485_RXD 4 14 | #define RS485_TXD 2 15 | #define RS485_TXEN 3 // Transmit-Enable 16 | 17 | #include 18 | #include 19 | HBWSoftwareSerial rs485(RS485_RXD, RS485_TXD); // RX, TX 20 | 21 | #define BUTTON 8 // Button fuer Factory-Reset etc. 22 | #define LED LED_BUILTIN // Signal-LED 23 | 24 | #define Key1 A0 25 | #define Key2 A1 26 | #define Key3 A2 27 | #define Key4 A3 28 | #define Key5 A4 29 | #define Key6 A5 30 | #define Key7 5 31 | #define Key8 6 32 | #define Key9 7 33 | #define Key10 9 34 | #define Key11 10 35 | #define Key12 11 36 | 37 | -------------------------------------------------------------------------------- /HBW-Sen-SC-12-DR/HBW-Sen-SC-12-DR.ino: -------------------------------------------------------------------------------- 1 | //******************************************************************* 2 | // 3 | // hbw_sen_sc_12_dr 4 | // 5 | // DANKSAGUNG: 6 | // Diese Arbeit basiert sich auf HBW-SC-10-Dim-6 und wurde mit Hilfe von loetmeister und 7 | // Tutorial und Hilfe von Thorsten (Mamber FHEM Forum "Thorsten Pferdekaemper") fertiggestellt. 8 | // Hiermit bedanke ich mich bei Thorsten und loetmeister für die hervorragende Arbeit mit HomeBrewWired und das Tutorial. 9 | // 10 | // Homematic Wired Hombrew Hardware 11 | // Arduino NANO als Homematic-Device 12 | // 12 digitale Eingänge (Key/Taster & Sensor) & Sensorkontakte 13 | // Diese Arbeit basiert sich auf HBW-SC-10-Dim-6 und wurde mit Hilfe von loetmeister und 14 | // Tutorial und Hilfe von Thorsten (Mamber FHEM Forum "Thorsten Pferdekaemper") 15 | // 16 | // Juri - JARA Armenia 17 | 18 | 19 | #define HARDWARE_VERSION 0x01 20 | #define FIRMWARE_VERSION 0x003C 21 | #define HMW_DEVICETYPE 0xA6 // device ID (make sure to import hbw_sen_sc_12_dr.xml into FHEM) 22 | 23 | #define NUMBER_OF_INPUT_CHAN 12 // input channel - pushbutton, key, other digital in 24 | #define NUMBER_OF_SEN_INPUT_CHAN 12 // equal number of sensor channels, using same ports/IOs as INPUT_CHAN 25 | 26 | #define NUM_LINKS_INPUT 20 // address step 6 27 | #define LINKADDRESSSTART_INPUT 0x038 // ends @0x0C7 28 | 29 | 30 | // HB Wired protocol and module 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | 38 | // Pins and hardware config 39 | #include "HBW-Sen-SC-12-DR_config_example.h" // When using custom device pinout or controller, copy this file and include it instead 40 | 41 | 42 | #define NUMBER_OF_CHAN NUMBER_OF_INPUT_CHAN + NUMBER_OF_SEN_INPUT_CHAN 43 | 44 | 45 | struct hbw_config { 46 | uint8_t logging_time; // 0x01 47 | uint32_t central_address; // 0x02 - 0x05 48 | uint8_t direct_link_deactivate:1; // 0x06:0 49 | uint8_t :7; // 0x06:1-7 50 | 51 | hbw_config_senSC senCfg[NUMBER_OF_SEN_INPUT_CHAN]; // 0x07 - 0x12 (address step 1) 52 | hbw_config_key keyCfg[NUMBER_OF_INPUT_CHAN]; // 0x13 - 0x2A (address step 2) 53 | 54 | } hbwconfig; 55 | 56 | 57 | HBWChannel* channels[NUMBER_OF_CHAN]; // total number of channels for the device 58 | 59 | HBWDevice* device = NULL; 60 | 61 | 62 | void setup() 63 | { 64 | // create channels 65 | 66 | #if NUMBER_OF_INPUT_CHAN == 12 && NUMBER_OF_SEN_INPUT_CHAN == 12 67 | static const uint8_t digitalInput[12] = {IO1, IO2, IO3, IO4, IO5, IO6, IO7, IO8, IO9, IO10, IO11, IO12}; // assing pins 68 | 69 | // input sensor and key channels 70 | for(uint8_t i = 0; i < NUMBER_OF_SEN_INPUT_CHAN; i++) { 71 | channels[i] = new HBWSenSC(digitalInput[i], &(hbwconfig.senCfg[i]), true); 72 | channels[i + NUMBER_OF_SEN_INPUT_CHAN] = new HBWKey(digitalInput[i], &(hbwconfig.keyCfg[i])); 73 | }; 74 | #else 75 | #error Input channel count and pin missmatch! 76 | #endif 77 | 78 | 79 | #ifdef USE_HARDWARE_SERIAL // RS485 via UART Serial, no debug (_debugstream is NULL) 80 | Serial.begin(19200, SERIAL_8E1); 81 | 82 | device = new HBWDevice(HMW_DEVICETYPE, HARDWARE_VERSION, FIRMWARE_VERSION, 83 | &Serial, RS485_TXEN, sizeof(hbwconfig), &hbwconfig, 84 | NUMBER_OF_CHAN, (HBWChannel**)channels, 85 | NULL, 86 | new HBWLinkKey(), NULL); 87 | 88 | device->setConfigPins(BUTTON, LED); 89 | 90 | #else 91 | Serial.begin(115200); // Serial->USB for debug 92 | rs485.begin(19200); // RS485 via SoftwareSerial, must use 19200 baud! 93 | 94 | device = new HBWDevice(HMW_DEVICETYPE, HARDWARE_VERSION, FIRMWARE_VERSION, 95 | &rs485, RS485_TXEN, sizeof(hbwconfig), &hbwconfig, 96 | NUMBER_OF_CHAN, (HBWChannel**)channels, 97 | &Serial, 98 | new HBWLinkKey(), NULL); 99 | 100 | device->setConfigPins(BUTTON, LED); // 8 (button) and 13 (led) is the default 101 | //device->setStatusLEDPins(LED, LED); // Tx, Rx LEDs 102 | 103 | hbwdebug(F("B: 2A ")); 104 | hbwdebug(freeRam()); 105 | hbwdebug(F("\n")); 106 | #endif 107 | } 108 | 109 | 110 | void loop() 111 | { 112 | device->loop(); 113 | POWERSAVE(); // go sleep a bit 114 | }; 115 | -------------------------------------------------------------------------------- /HBW-Sen-SC-12-DR/HBW-Sen-SC-12-DR_config_example.h: -------------------------------------------------------------------------------- 1 | /* Default / example configuation file. When using custom device config (pinout, EEPROM, etc.) or controller, 2 | * copy this file and adjust it. This would also avoid to owerwrite it with new versions from GitHub. */ 3 | 4 | // Arduino NANO / ATMega 328p config - RS485 bus is attached to SoftwareSerial by default, UART0 is used for serial debug. 5 | 6 | EEPROMClass* EepromPtr = &EEPROM; // use internal EEPROM 7 | 8 | // #define USE_HARDWARE_SERIAL // use hardware serial (USART) for final device - this disables debug output 9 | /* Undefine "HBW_DEBUG" in 'HBWired.h' to remove unneeded code. "HBW_DEBUG" also works as master switch, 10 | * as hbwdebug() or hbwdebughex() used in channels will point to empty functions. */ 11 | 12 | // Pins 13 | #define IO1 A3 14 | #define IO2 10 15 | #define IO3 11 16 | #define IO4 A0 17 | #define IO5 A1 18 | #define IO6 A2 19 | #define IO7 A4 20 | #define IO8 A5 21 | #define IO9 9 22 | #define IO10 7 23 | #define IO11 6 24 | #define IO12 5 25 | 26 | #define LED LED_BUILTIN // Signal-LED 27 | 28 | #ifdef USE_HARDWARE_SERIAL 29 | #define RS485_TXEN 2 // Transmit-Enable 30 | #define BUTTON A6 // Button fuer Factory-Reset etc. 31 | 32 | #else 33 | #define RS485_RXD 4 34 | #define RS485_TXD 2 35 | #define RS485_TXEN 3 // Transmit-Enable 36 | #define BUTTON 8 // Button fuer Factory-Reset etc. 37 | 38 | #include "FreeRam.h" 39 | #include 40 | HBWSoftwareSerial rs485(RS485_RXD, RS485_TXD); // RX, TX 41 | #endif 42 | 43 | 44 | -------------------------------------------------------------------------------- /HBW-Sen-SC-12-DR/readme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThorstenPferdekaemper/HBWired/27cbac299529a660c791c42f2cece74439513561/HBW-Sen-SC-12-DR/readme.txt -------------------------------------------------------------------------------- /HBW-WDS-C7/HBW-WDS-C7_latest.ino_50MHz.uf2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThorstenPferdekaemper/HBWired/27cbac299529a660c791c42f2cece74439513561/HBW-WDS-C7/HBW-WDS-C7_latest.ino_50MHz.uf2 -------------------------------------------------------------------------------- /HBW-WDS-C7/HBWSIGNALDuino_adv.cpp: -------------------------------------------------------------------------------- 1 | // Homematic Wired Hombrew (HBW), with SIGNALDuino advanced 2 | // loetmeister.de - 2024.07.14 3 | 4 | #include "HBWSIGNALDuino_adv.h" 5 | 6 | // def 7 | HBWSIGNALDuino_adv::HBWSIGNALDuino_adv(uint8_t _pin_receive, uint8_t _pin_send, uint8_t _pin_led, hbw_config_signalduino_adv* _config) { 8 | pin_receive = _pin_receive; 9 | pin_led = _pin_led; 10 | config = _config; 11 | // clearFeedback(); 12 | // currentState = UNKNOWN_STATE; 13 | }; 14 | 15 | 16 | // channel specific settings or defaults 17 | // (This function is called after device read config from EEPROM) 18 | void HBWSIGNALDuino_adv::afterReadConfig() { 19 | // hbwdebug(F("SIGNALDuino_adv conf - ot: "));hbwdebug(config->offTime);hbwdebug(F("\n")); 20 | // if (currentState == UNKNOWN_STATE) { 21 | // // All off on init, but consider inverted setting 22 | // digitalWrite(pin, config->n_inverted ? LOW : HIGH); // 0=inverted, 1=not inverted (device reset will set to 1!) 23 | // pinMode(pin,OUTPUT); 24 | // currentState = OFF_STATE; 25 | // } 26 | // else { 27 | // // Do not reset outputs on config change (EEPROM re-reads), but update its state 28 | // digitalWrite(pin, !currentState ^ config->n_inverted); 29 | // } 30 | } 31 | 32 | 33 | void HBWSIGNALDuino_adv::set(HBWDevice* device, uint8_t length, uint8_t const * const data) { 34 | // if (config->output_unlocked) { //0=LOCKED, 1=UNLOCKED 35 | // if(*data > 200) { // toggle 36 | // digitalWrite(pin, digitalRead(pin) ? LOW : HIGH); // TODO: force offTime... 37 | // currentState = (currentState ? OFF_STATE : ON_STATE); 38 | // } 39 | // else { // on or off 40 | // if (*data) { 41 | // if (millis() - lastOnOffTime >= 4000) { // TODO: use config->offTime 42 | // digitalWrite(pin, LOW ^ config->n_inverted); // on (if not inverted) 43 | // currentState = ON_STATE; 44 | // lastOnOffTime = millis(); 45 | // } 46 | // } 47 | // else { 48 | // digitalWrite(pin, HIGH ^ config->n_inverted); // off (if not inverted) 49 | // currentState = OFF_STATE; 50 | // } 51 | // } 52 | // } 53 | // Logging 54 | // set trigger to send info/notify message in loop() 55 | // setFeedback(device, config->logging); 56 | }; 57 | 58 | 59 | uint8_t HBWSIGNALDuino_adv::get(uint8_t* data) { 60 | // if (currentState) 61 | (*data) = 200; 62 | // else 63 | // (*data) = 0; 64 | return 1; 65 | }; 66 | 67 | 68 | void HBWSIGNALDuino_adv::loop(HBWDevice* device, uint8_t channel) { 69 | 70 | // if (millis() - lastOnOffTime >= 3000 && currentState == ON_STATE) { // TODO: use config->onTime 71 | // lastOnOffTime = millis(); 72 | // uint8_t value = 0; 73 | // set(device, 1, &value); // set off 74 | // } 75 | // feedback trigger set? 76 | // checkFeedback(device, channel); 77 | }; 78 | -------------------------------------------------------------------------------- /HBW-WDS-C7/HBWSIGNALDuino_adv.h: -------------------------------------------------------------------------------- 1 | // TODO 2 | // placheholder - chan should allow basic config for SIGNALDuino, like mode, frequency, bWidth, etc. 3 | 4 | #ifndef HBWSIGNALDuino_adv_h 5 | #define HBWSIGNALDuino_adv_h 6 | 7 | #include 8 | #include 9 | 10 | 11 | // config of one channel, address step ? 16 (must be multiple of four) 12 | struct hbw_config_signalduino_adv { 13 | uint8_t unused; // +0 14 | uint8_t rfmode:4; // rfmodeTesting 0...15 (15 = default) 15 | uint8_t fillup:4; 16 | uint16_t cc_bWidth; 17 | uint16_t cc_freq; // cc1101_frequency (0...65534 +30000 = 340.00 to 995.34 MHz) 18 | uint32_t dummyx; 19 | uint32_t dummyz; 20 | // TODO allow to set frequency and other options? (use bank0, other bank for other channels?) 21 | }; 22 | 23 | 24 | class HBWSIGNALDuino_adv : public HBWChannel { 25 | public: 26 | HBWSIGNALDuino_adv(uint8_t _pin_receive, uint8_t _pin_send, uint8_t _pin_led, hbw_config_signalduino_adv* _config); 27 | virtual void loop(HBWDevice*, uint8_t channel); 28 | virtual uint8_t get(uint8_t* data); 29 | virtual void set(HBWDevice* device, uint8_t length, uint8_t const * const data); 30 | virtual void afterReadConfig(); 31 | 32 | private: 33 | uint8_t pin_receive, pin_send, pin_led; 34 | // uint8_t currentState; // keep track of logical state, not real IO 35 | hbw_config_signalduino_adv* config; 36 | uint32_t lastOnOffTime; 37 | 38 | // static const unsigned char* Bresser_5in1_u_7in1__B26_N7_8220[] = {'CW0001,0246,0306,042D,05D4,061A,07C0,0800,0D21,0E65,0FE8,1088,114C,1202,1322,14F8,1551,1700,1818,1916,1B43,1C68,1D91,23E9,242A,2500,2611,3D07,3E01,4042,4172,4265,4373,4473,4535,4631,4700'}; 39 | // static const unsigned char* rfmode[] = {Bresser_5in1_u_7in1__B26_N7_8220}; 40 | }; 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /HBW-WDS-C7/HBWSIGNALDuino_adv/SimpleFIFO.h: -------------------------------------------------------------------------------- 1 | #ifndef SimpleFIFO_h 2 | #define SimpleFIFO_h 3 | #include 4 | #ifndef SIMPLEFIFO_SIZE_TYPE 5 | #ifndef SIMPLEFIFO_LARGE 6 | #define SIMPLEFIFO_SIZE_TYPE uint8_t 7 | #else 8 | #define SIMPLEFIFO_SIZE_TYPE uint16_t 9 | #endif 10 | #endif 11 | /* 12 | || 13 | || @file SimpleFIFO.h 14 | || @version 1.2 15 | || @author Alexander Brevig 16 | || @contact alexanderbrevig@gmail.com 17 | || 18 | || @description 19 | || | A simple FIFO class, mostly for primitive types but can be used with classes if assignment to int is allowed 20 | || | This FIFO is not dynamic, so be sure to choose an appropriate size for it 21 | || # 22 | || 23 | || @license 24 | || | Copyright (c) 2010 Alexander Brevig 25 | || | This library is free software; you can redistribute it and/or 26 | || | modify it under the terms of the GNU Lesser General Public 27 | || | License as published by the Free Software Foundation; version 28 | || | 2.1 of the License. 29 | || | 30 | || | This library is distributed in the hope that it will be useful, 31 | || | but WITHOUT ANY WARRANTY; without even the implied warranty of 32 | || | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 33 | || | Lesser General Public License for more details. 34 | || | 35 | || | You should have received a copy of the GNU Lesser General Public 36 | || | License along with this library; if not, write to the Free Software 37 | || | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 38 | || # 39 | || 40 | */ 41 | template 42 | class SimpleFIFO { 43 | public: 44 | const SIMPLEFIFO_SIZE_TYPE size; //speculative feature, in case it's needed 45 | 46 | SimpleFIFO(); 47 | 48 | T dequeue(); //get next element 49 | bool enqueue( T element ); //add an element 50 | T peek() const; //get the next element without releasing it from the FIFO 51 | void flush(); //[1.1] reset to default state 52 | 53 | //how many elements are currently in the FIFO? 54 | SIMPLEFIFO_SIZE_TYPE count() { return numberOfElements; } 55 | 56 | private: 57 | #ifndef SimpleFIFO_NONVOLATILE 58 | volatile SIMPLEFIFO_SIZE_TYPE numberOfElements; 59 | volatile SIMPLEFIFO_SIZE_TYPE nextIn; 60 | volatile SIMPLEFIFO_SIZE_TYPE nextOut; 61 | volatile T raw[rawSize]; 62 | #else 63 | SIMPLEFIFO_SIZE_TYPE numberOfElements; 64 | SIMPLEFIFO_SIZE_TYPE nextIn; 65 | SIMPLEFIFO_SIZE_TYPE nextOut; 66 | T raw[rawSize]; 67 | #endif 68 | }; 69 | 70 | template 71 | SimpleFIFO::SimpleFIFO() : size(rawSize) { 72 | flush(); 73 | } 74 | template 75 | bool SimpleFIFO::enqueue( T element ) { 76 | if ( count() >= rawSize ) { return false; } 77 | numberOfElements++; 78 | nextIn %= size; 79 | raw[nextIn] = element; 80 | nextIn++; //advance to next index 81 | return true; 82 | } 83 | template 84 | T SimpleFIFO::dequeue() { 85 | numberOfElements--; 86 | nextOut %= size; 87 | return raw[ nextOut++]; 88 | } 89 | template 90 | T SimpleFIFO::peek() const { 91 | return raw[ nextOut % size]; 92 | } 93 | template 94 | void SimpleFIFO::flush() { 95 | nextIn = nextOut = numberOfElements = 0; 96 | } 97 | #endif 98 | -------------------------------------------------------------------------------- /HBW-WDS-C7/HBWSIGNALDuino_adv/compile_config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Config flags for compiling correct options / boards Define only one 4 | 5 | //#define ARDUINO_ATMEGA328P_MINICUL 1 6 | //#define ARDUINO_AVR_ICT_BOARDS_ICT_BOARDS_AVR_RADINOCC1101 1 7 | //#define ARDUINO_BUSWARE_CUL 1 // BusWare CUL V3 (ATmega32U4) 8 | //#define OTHER_BOARD_WITH_CC1101 1 9 | #define RASPBERRY_PI_PICO 1 10 | 11 | 12 | //#define DEBUGSENDCMD 1 13 | //#define SENDTODECODER 1 // damit wird in der send_raw Routine anstatt zu senden, die Pulse direkt dem Decoder uebergeben 14 | 15 | //#define WATCHDOG 1 // Der Watchdog ist in der Entwicklungs und Testphase deaktiviert. Es muss auch ohne Watchdog stabil funktionieren. 16 | //#define CMP_MEMDBG 1 17 | 18 | // --------------------------------------- 19 | // Do not Change anything below this line 20 | 21 | #ifdef OTHER_BOARD_WITH_CC1101 22 | #define CMP_CC1101 23 | #endif 24 | #ifdef RASPBERRY_PI_PICO 25 | #define CMP_CC1101 26 | #endif 27 | #ifdef ARDUINO_ATMEGA328P_MINICUL 28 | #define CMP_CC1101 29 | #endif 30 | #ifdef ARDUINO_AVR_ICT_BOARDS_ICT_BOARDS_AVR_RADINOCC1101 31 | #define CMP_CC1101 32 | #define ONLY_FSK 33 | #endif 34 | #ifdef ARDUINO_BUSWARE_CUL 35 | #define CMP_CC1101 36 | #define ONLY_FSK 37 | #endif 38 | -------------------------------------------------------------------------------- /HBW-WDS-C7/HBWSIGNALDuino_adv/output.h: -------------------------------------------------------------------------------- 1 | // output.h 2 | #ifndef _OUTPUT_h 3 | #define _OUTPUT_h 4 | 5 | #if !defined(MAPLE_Mini) && !defined(ESP32) && !defined(ARDUINO_ARCH_RP2040) 6 | #define portOfPin(P)\ 7 | (((P)>=0&&(P)<8)?&PORTD:(((P)>7&&(P)<14)?&PORTB:&PORTC)) 8 | #define ddrOfPin(P)\ 9 | (((P)>=0&&(P)<8)?&DDRD:(((P)>7&&(P)<14)?&DDRB:&DDRC)) 10 | #define pinOfPin(P)\ 11 | (((P)>=0&&(P)<8)?&PIND:(((P)>7&&(P)<14)?&PINB:&PINC)) 12 | #define pinIndex(P)((uint8_t)(P>13?P-14:P&7)) 13 | #endif 14 | 15 | #if !defined(MAPLE_Mini) && !defined(ESP32) && !defined(ARDUINO_ARCH_RP2040) 16 | #define pinMask(P)((uint8_t)(1<0) 23 | #define isLow(P)((*(pinOfPin(P))& pinMask(P))==0) 24 | #define digitalState(P)((uint8_t)isHigh(P)) 25 | #elif defined(MAPLE_Mini) 26 | #define pinAsInput(pin) pinMode(pin, INPUT) 27 | #define pinAsOutput(pin) pinMode(pin, OUTPUT) 28 | #define pinAsInputPullUp(pin) pinMode(pin, INPUT_PULLUP) 29 | #define digitalLow(pin) digitalWrite(pin, LOW) 30 | #define digitalHigh(pin) digitalWrite(pin, HIGH) 31 | #define isHigh(pin) (digitalRead(pin) == HIGH) 32 | #define isLow(pin) (digitalRead(pin) == LOW) 33 | #else 34 | // ESP32 or ARDUINO_ARCH_RP2040 35 | #define pinAsInput(pin) pinMode(pin, INPUT) 36 | #define pinAsOutput(pin) pinMode(pin, OUTPUT) 37 | #define pinAsInputPullUp(pin) pinMode(pin, INPUT_PULLUP) 38 | 39 | #ifndef digitalLow 40 | #define digitalLow(pin) digitalWrite(pin, LOW) 41 | #endif 42 | #ifndef digitalHigh 43 | #define digitalHigh(pin) digitalWrite(pin, HIGH) 44 | #endif 45 | #ifndef isHigh 46 | #define isHigh(pin) (digitalRead(pin) == HIGH) 47 | #endif 48 | #ifndef isLow 49 | #define isLow(pin) (digitalRead(pin) == LOW) 50 | #endif 51 | #endif 52 | 53 | //#define DEBUG 54 | 55 | #if defined(ARDUINO) && ARDUINO >= 100 56 | #include "Arduino.h" 57 | #else 58 | // #include "WProgram.h" 59 | #endif 60 | 61 | #ifdef ETHERNET_PRINT 62 | #include 63 | 64 | extern WiFiClient serverClient; 65 | 66 | 67 | #define MSG_PRINTER serverClient // Not Implemented at this time 68 | #else 69 | #define MSG_PRINTER Serial 70 | #endif 71 | 72 | #ifdef ETHERNET_DEBUG 73 | #define DBG_PRINTER Client // Not Implemented at this time 74 | #else 75 | #define DBG_PRINTER Serial 76 | #endif 77 | 78 | 79 | #define MSG_PRINT(...) { MSG_PRINTER.print(__VA_ARGS__); } 80 | #define MSG_PRINTLN(...) { MSG_PRINTER.println(__VA_ARGS__); } 81 | #define MSG_WRITE(...) { MSG_PRINTER.write(__VA_ARGS__); } 82 | 83 | #ifdef DEBUG 84 | #define DBG_PRINT(...) { DBG_PRINTER.print(__VA_ARGS__); } 85 | #define DBG_PRINTLN(...) { DBG_PRINTER.println(__VA_ARGS__); } 86 | #else 87 | #define DBG_PRINT(...) 88 | #define DBG_PRINTLN(...) 89 | #endif 90 | 91 | 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /HBW-WDS-C7/HBWSIGNALDuino_adv/signalDecoder.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Pattern Decoder Library V3 3 | * Library to decode radio signals based on patternd detection 4 | * 2014-2015 N.Butzek, S.Butzek 5 | * 2015-2017 S.Butzek 6 | 7 | * This library contains classes to perform decoding of digital signals 8 | * typical for home automation. The focus for the moment is on different sensors 9 | * like weather sensors (temperature, humidity Logilink, TCM, Oregon Scientific, ...), 10 | * remote controlled power switches (Intertechno, TCM, ARCtech, ...) which use 11 | * encoder chips like PT2262 and EV1527-type and manchester encoder to send 12 | * information in the 433MHz or 868 Mhz Band. 13 | * 14 | * The classes in this library follow the approach to detect a recurring pattern in the 15 | * recived signal. For Manchester there is a class which decodes the signal. 16 | * 17 | * This program is free software: you can redistribute it and/or modify 18 | * it under the terms of the GNU General Public License as published by 19 | * the Free Software Foundation, either version 3 of the License, or 20 | * (at your option) any later version. 21 | * 22 | * This program is distributed in the hope that it will be useful, 23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | * GNU General Public License for more details. 26 | * 27 | * You should have received a copy of the GNU General Public License 28 | * along with this program. If not, see . 29 | 30 | */ 31 | #include "signalDecoder.h" 32 | -------------------------------------------------------------------------------- /HBW-WDS-C7/bit_util.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | Various utility functions for use by device drivers. 3 | 4 | Copyright (C) 2015 Tommy Vestermark 5 | 6 | This program is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | */ 11 | 12 | #include "bit_util.h" 13 | -------------------------------------------------------------------------------- /HBW-WDS-C7/readme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThorstenPferdekaemper/HBWired/27cbac299529a660c791c42f2cece74439513561/HBW-WDS-C7/readme.txt -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HBWired 2 | ### The HomeBrewWired Protocol 3 | HBWired is the implementation of a communications protocol for Arduino and similar. The protocol happens to be compatible with Homematic Wired. 4 | -------------------------------------------------------------------------------- /documentation/arduino_nano/mega328p_fuses-detailed_Engbedded.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThorstenPferdekaemper/HBWired/27cbac299529a660c791c42f2cece74439513561/documentation/arduino_nano/mega328p_fuses-detailed_Engbedded.pdf -------------------------------------------------------------------------------- /documentation/arduino_nano/mega328p_fuses.txt: -------------------------------------------------------------------------------- 1 | ##NANO specific default fuses (AtMega328p, 16Mhz crystal + bootloader) 2 | 3 | Device signature = 0x1e950f (probably m328p) 4 | safemode: hfuse reads as DA 5 | safemode: efuse reads as FD 6 | safemode: Fuses OK (E:FD, H:DA, L:FF) 7 | 8 | 9 | ##Quick command reference 10 | 11 | AVRDUDE arguments, 12 | to set fuses... 13 | To set default fuses: 14 | avrdude -c AVRISPmkII -p m328p -U lfuse:w:0xff:m -U hfuse:w:0xda:m -U efuse:w:0xfd:m 15 | 16 | To preserve EEPROM memory through the Chip Erase cycle; [EESAVE] - use hfuse = 0xD2: 17 | avrdude.exe -c AVRISPmkII -p m328p -U lfuse:w:0xff:m -U hfuse:w:0xd2:m -U efuse:w:0xfd:m 18 | 19 | -->> this is used on https://loetmeister.de/Elektronik/homematic/index.htm#modules <<-- 20 | To disable bootloader & preserve EEPROM memory: 21 | avrdude -c AVRISPmkII -p m328p -U lfuse:w:0xff:m -U hfuse:w:0xd3:m -U efuse:w:0xfd:m 22 | 23 | 24 | to flash... 25 | (no boot loader version): 26 | avrdude -c AVRISPmkII -p m328p -U flash:w:HBW-device.ino.eightanaloginputs.hex:i -v 27 | 28 | -------------------------------------------------------------------------------- /documentation/arduino_nano/mega328pb_fuses.txt: -------------------------------------------------------------------------------- 1 | default fuses (AtMega328pb) - stock 2 | 3 | avrdude: Device signature = 0x1e9516 (probably m328pb) 4 | avrdude: safemode: lfuse reads as 62 5 | avrdude: safemode: hfuse reads as D9 6 | avrdude: safemode: efuse reads as F7 7 | avrdude: safemode: Fuses OK (E:F7, H:D9, L:62) 8 | 9 | 10 | custom fuses: 11 | CFD = CFD_ENABLED 12 | BODLEVEL = 2V7 13 | RSTDISBL = [ ] 14 | DWEN = [ ] 15 | SPIEN = [X] 16 | WDTON = [ ] 17 | EESAVE = [X] 18 | BOOTSZ = 1024W_3C00 19 | BOOTRST = [ ] 20 | CKDIV8 = [ ] 21 | CKOUT = [ ] 22 | SUT_CKSEL = EXTXOSC_8MHZ_XX_16KCK_14CK_65MS 23 | 24 | EXTENDED = 0xFD (valid) 25 | HIGH = 0xD3 (valid) 26 | LOW = 0xFF (valid) 27 | 28 | 29 | ##Quick command reference 30 | 31 | AVRDUDE arguments, 32 | to set fuses... 33 | 34 | (same as m328p) 35 | 36 | -->> this is used on https://loetmeister.de/Elektronik/homematic/index.htm#modules <<-- 37 | To disable bootloader & preserve EEPROM memory: 38 | avrdude -c AVRISPmkII -p m328pb -U lfuse:w:0xff:m -U hfuse:w:0xd3:m -U efuse:w:0xfd:m 39 | 40 | --> efuse: 0xfd may not be accepted. User other tools, e.g. Atmel Studio 41 | 42 | 43 | to flash... 44 | (no boot loader version): 45 | avrdude -c AVRISPmkII -p m328pb -U flash:w:HBW-device.ino.eightanaloginputs.hex:i -v 46 | 47 | -------------------------------------------------------------------------------- /documentation/quick-setup.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThorstenPferdekaemper/HBWired/27cbac299529a660c791c42f2cece74439513561/documentation/quick-setup.txt -------------------------------------------------------------------------------- /libraries/ClickButton/Examples/LEDfader/LEDfader.ino: -------------------------------------------------------------------------------- 1 | /* ClickButton LED fader demo 2 | 3 | LED on/off and fading up/down via one button 4 | 5 | Short press turns LED on or off. 6 | Long press (over one second) fades the LED and changes direction for each press 7 | 8 | The circuit: 9 | - LED attached from pin 10 to resistor (say 220-ish ohms), other side of resistor to GND (ground) 10 | - Pushbutton attached from pin 4 to GND 11 | No pullup resistor needed, using the Arduino's (Atmega's) internal pullup resistor in this example. 12 | 13 | 14 | 2013.02.17 - raron 15 | */ 16 | 17 | #include "ClickButton.h" 18 | 19 | 20 | // the LED 21 | const int ledPin = 10; 22 | int ledState = 0; 23 | 24 | // the Button 25 | const int buttonPin1 = 4; 26 | ClickButton button1(buttonPin1, LOW, CLICKBTN_PULLUP); 27 | 28 | // Fade variables 29 | int fadeValue = 64; 30 | boolean fadeUp = false; // false means fade down 31 | boolean oldFadeUp = fadeUp; 32 | const long fadeDelay = 10; // Time in milliseconds between fade steps 33 | long adjustFaderTime = 0; // Time to adjust the fader 34 | 35 | // other 36 | long currentTime; 37 | int function = 0; 38 | 39 | 40 | void setup() 41 | { 42 | pinMode(ledPin,OUTPUT); 43 | } 44 | 45 | 46 | void loop() 47 | { 48 | currentTime = (long)millis(); 49 | 50 | button1.Update(); 51 | 52 | if (button1.clicks != 0) function = button1.clicks; 53 | 54 | // Toggle LED on single clicks 55 | if(button1.clicks == 1) ledState = !ledState; 56 | 57 | // fade if button is held down during single-click 58 | if(function == -1 && button1.depressed == true) 59 | { 60 | ledState = true; // force lights on, since we want to fade it up or down 61 | 62 | if (oldFadeUp == fadeUp) fadeUp = !fadeUp; // Switch direction 63 | 64 | if ( currentTime - adjustFaderTime > fadeDelay) 65 | { 66 | adjustFaderTime = currentTime + fadeDelay; 67 | if (fadeUp) fadeValue++; else fadeValue--; 68 | 69 | // Some boundary checking 70 | // Using signed ints, we can check for below 0 and above 255 (byte limit) 71 | if (fadeValue > 255) fadeValue = 255; 72 | if (fadeValue < 0) fadeValue = 0; 73 | 74 | } 75 | 76 | } else { 77 | // Save old fade direction for next time 78 | oldFadeUp = fadeUp; 79 | // Reset function 80 | function = 0; 81 | } 82 | 83 | 84 | // update the LED 85 | if (ledState) analogWrite(ledPin,fadeValue); else analogWrite(ledPin, 0); 86 | } 87 | -------------------------------------------------------------------------------- /libraries/ClickButton/Examples/MultiButtons/MultiButtons.ino: -------------------------------------------------------------------------------- 1 | /* ClickButton library demo 2 | 3 | Demo of multiple ClickButton objects in an array. 4 | Same as MultiClicks example, but with 3 buttons and 3 LED's. 5 | 6 | Short clicks: 7 | 8 | Single click - Toggle LED on/off 9 | Double click - Blink (Toggles LED 2 times/second) 10 | Triple click - Fast blink (Toggles LED 5 times/second) 11 | 12 | Long clicks (hold button for one second or longer on last click): 13 | 14 | Single-click - Slow blink (Toggles LED every second) 15 | Double-click - Sloow blink (Toggles LED every other second) 16 | Triple-click - Slooow blink (Toggles LED every three seconds) 17 | 18 | 19 | The circuit: 20 | - LEDs attached from pin 10,11 and 12 to resistors (say 220-ish ohms), other side of resistors to GND (ground) 21 | - Pushbuttons attached from pin 4,5 and 6 to GND 22 | No pullup resistor needed, using the Arduino's (Atmega's) internal pullup resistor in this example. 23 | 24 | Based on the Arduino Debounce example. 25 | 26 | 2010, 2013 raron 27 | 28 | GNU GPLv3 license 29 | */ 30 | 31 | #include "ClickButton.h" 32 | 33 | // Nr. of buttons in the array 34 | const int buttons = 3; 35 | 36 | // the LED 37 | const int ledPin[buttons] = { 10, 11, 12 }; // Arduino pins to the LEDs 38 | int ledState[buttons] = { 0, 0, 0 }; 39 | int LEDfunction[buttons] = { 0, 0, 0 }; 40 | 41 | // Arduino input pins from the buttons (these are not in an array for simplicity just now) 42 | const int buttonPin1 = 4; 43 | const int buttonPin2 = 5; 44 | const int buttonPin3 = 6; 45 | 46 | // Instantiate ClickButton objects in an array 47 | ClickButton button[3] = { 48 | ClickButton (buttonPin1, LOW, CLICKBTN_PULLUP), 49 | ClickButton (buttonPin2, LOW, CLICKBTN_PULLUP), 50 | ClickButton (buttonPin3, LOW, CLICKBTN_PULLUP), 51 | }; 52 | 53 | 54 | 55 | 56 | void setup() 57 | { 58 | for (int i=0; i 33 | // #include 34 | // #include 35 | #include 36 | 37 | 38 | // Block select modes. 39 | #define EE_BSEL_NONE 0 40 | #define EE_BSEL_8BIT_ADDR 1 41 | #define EE_BSEL_17BIT_ADDR 2 42 | #define EE_BSEL_17BIT_ADDR_ALT 3 43 | 44 | // Create an EEPROM descriptor from byte size, page size, and block select mode. 45 | #define _EE24(byteSize, pageSize, mode) \ 46 | (((byteSize) / (pageSize)) | (((unsigned long)(pageSize)) << 16) | \ 47 | (((unsigned long)(mode)) << 28)) 48 | 49 | // Type descriptors for the 24LCXX range of EEPROM's. 50 | #define EEPROM_24LC00 _EE24(16UL, 1, EE_BSEL_8BIT_ADDR) 51 | #define EEPROM_24LC01 _EE24(128UL, 8, EE_BSEL_8BIT_ADDR) 52 | #define EEPROM_24LC014 _EE24(128UL, 16, EE_BSEL_8BIT_ADDR) 53 | #define EEPROM_24LC02 _EE24(256UL, 8, EE_BSEL_8BIT_ADDR) 54 | #define EEPROM_24LC024 _EE24(256UL, 16, EE_BSEL_8BIT_ADDR) 55 | #define EEPROM_24LC025 _EE24(256UL, 16, EE_BSEL_8BIT_ADDR) 56 | #define EEPROM_24LC04 _EE24(512UL, 16, EE_BSEL_8BIT_ADDR) 57 | #define EEPROM_24LC08 _EE24(1024UL, 16, EE_BSEL_8BIT_ADDR) 58 | #define EEPROM_24LC16 _EE24(2048UL, 16, EE_BSEL_8BIT_ADDR) 59 | #define EEPROM_24LC32 _EE24(4096UL, 32, EE_BSEL_NONE) 60 | #define EEPROM_24LC64 _EE24(8192UL, 32, EE_BSEL_NONE) 61 | #define EEPROM_24LC128 _EE24(16384UL, 32, EE_BSEL_NONE) 62 | #define EEPROM_24LC256 _EE24(32768UL, 64, EE_BSEL_NONE) 63 | #define EEPROM_24LC512 _EE24(65536UL, 128, EE_BSEL_NONE) 64 | #define EEPROM_24LC1025 _EE24(131072UL, 128, EE_BSEL_17BIT_ADDR_ALT) 65 | #define EEPROM_24LC1026 _EE24(131072UL, 128, EE_BSEL_17BIT_ADDR) 66 | 67 | class EEPROM24 68 | { 69 | public: 70 | EEPROM24(TwoWire& bus, unsigned long type, uint8_t bank = 0); 71 | 72 | unsigned long size() const { return _size; } 73 | unsigned long pageSize() const { return _pageSize; } 74 | 75 | bool available(); 76 | bool isConnected(); 77 | 78 | uint8_t read(unsigned long address); 79 | size_t read(unsigned long address, void *data, size_t length); 80 | 81 | bool update(unsigned long address, uint8_t value); 82 | 83 | bool write(unsigned long address, uint8_t value); 84 | size_t write(unsigned long address, const void *data, size_t length); 85 | 86 | private: 87 | TwoWire* _bus; 88 | unsigned long _size; 89 | unsigned long _pageSize; 90 | uint8_t _mode; 91 | uint8_t i2cAddress; 92 | 93 | void writeAddress(unsigned long address); 94 | bool waitForWrite(); 95 | }; 96 | 97 | #endif 98 | -------------------------------------------------------------------------------- /libraries/README.md: -------------------------------------------------------------------------------- 1 | # HBWired 2 | ## The HomeBrewWired Protocol 3 | HBWired is the implementation of a communications protocol for Arduino and similar. The protocol happens to be compatible with Homematic Wired. 4 | 5 | ### Use library in Arduino IDE 6 | Copy the entire content of this path to (a newly created) HBWired folder in the Arduino "libraries" folder. (e.g. Arduino\libraries\HBWired) 7 | 8 | #### Additional resources 9 | To use EEPROM24 I2C lib, copy EEPROM24 folder to the Arduino "libraries" folder. -------------------------------------------------------------------------------- /libraries/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For ClickButton 3 | # & HBWired 4 | ####################################### 5 | 6 | ####################################### 7 | # Datatypes (KEYWORD1) 8 | ####################################### 9 | 10 | ClickButton KEYWORD1 11 | 12 | #HBWired 13 | HBWDevice KEYWORD1 14 | HBWChannel KEYWORD1 15 | HBWLinkSender KEYWORD1 16 | HBWLinkReceiver KEYWORD1 17 | 18 | ####################################### 19 | # Methods and Functions (KEYWORD2) 20 | ####################################### 21 | 22 | Update KEYWORD2 23 | 24 | #HBWired 25 | hbwdebughex KEYWORD2 26 | hbwdebug KEYWORD2 27 | set KEYWORD2 28 | get KEYWORD2 29 | setConfigPins KEYWORD2 30 | sendInfoMessage KEYWORD2 31 | sendKeyEvent KEYWORD2 32 | receiveKeyEvent KEYWORD2 33 | processEvent KEYWORD2 34 | afterReadConfig KEYWORD2 35 | setStatusLEDPins KEYWORD2 36 | getLoggingTime KEYWORD2 37 | 38 | ####################################### 39 | # Constants (LITERAL1) 40 | ####################################### 41 | 42 | CLICKBTN_PULLUP LITERAL1 43 | 44 | #HBWired 45 | JT_ONDELAY LITERAL1 46 | JT_RAMP_ON LITERAL1 47 | JT_ON LITERAL1 48 | JT_OFFDELAY LITERAL1 49 | JT_RAMP_OFF LITERAL1 50 | JT_OFF LITERAL1 51 | JT_NO_JUMP_IGNORE_COMMAND LITERAL1 52 | ON_TIME_ABSOLUTE LITERAL1 53 | OFF_TIME_ABSOLUTE LITERAL1 54 | ON_TIME_MINIMAL LITERAL1 55 | OFF_TIME_MINIMAL LITERAL1 56 | UNKNOWN_STATE LITERAL1 57 | FORCE_STATE_CHANGE LITERAL1 58 | 59 | ####################################### 60 | # Built in variables (LITERAL2) 61 | ####################################### 62 | 63 | clicks LITERAL2 64 | depressed LITERAL2 65 | maxPresses LITERAL2 66 | debounceTime LITERAL2 67 | multiclickTime LITERAL2 68 | longClickTime LITERAL2 69 | 70 | #HBWired 71 | HBWSoftwareSerial LITERAL2 72 | HBWAnalogIn LITERAL2 73 | HBWBlind LITERAL2 74 | HBWDimmerAdvanced LITERAL2 75 | HBWKey LITERAL2 76 | HBWSenEP LITERAL2 77 | HBWSenSC LITERAL2 78 | HBWOneWireTempSensors LITERAL2 79 | HBWPids LITERAL2 80 | HBWSwitch LITERAL2 81 | HBWSwitchAdvanced LITERAL2 82 | HBWValve LITERAL2 83 | HBWLinkBlindSimple LITERAL2 84 | HBWLinkDimmerAdvanced LITERAL2 85 | HBWLinkKey LITERAL2 86 | HBWLinkSwitchAdvanced LITERAL2 87 | HBWLinkSwitchSimple LITERAL2 88 | -------------------------------------------------------------------------------- /libraries/library.properties: -------------------------------------------------------------------------------- 1 | name=HBWired 2 | version=1.2.0 3 | author=Thorsten Pferdekaemper (thorsten@pferdekaemper.com) 4 | maintainer=Thorsten Pferdekaemper (thorsten@pferdekaemper.com) 5 | sentence=HBWired Homebrew 6 | paragraph=Build your own Homematic Wired bus Devices. 7 | category=Communication 8 | url=https://github.com/ThorstenPferdekaemper/HBWired 9 | architectures=* 10 | -------------------------------------------------------------------------------- /libraries/src/ClickButton.h: -------------------------------------------------------------------------------- 1 | #ifndef ClickButton_H 2 | #define ClickButton_H 3 | 4 | #if (ARDUINO < 100) 5 | #include 6 | #else 7 | #include 8 | #endif 9 | 10 | 11 | #define CLICKBTN_PULLUP HIGH 12 | 13 | 14 | class ClickButton 15 | { 16 | public: 17 | ClickButton(uint8_t buttonPin); 18 | ClickButton(uint8_t buttonPin, boolean active); 19 | ClickButton(uint8_t buttonPin, boolean active, boolean internalPullup); 20 | void Update(); 21 | int clicks; // button click counts to return 22 | boolean depressed; // the currently debounced button (press) state (presumably it is not sad :) 23 | long debounceTime; 24 | long multiclickTime; 25 | long longClickTime; 26 | private: 27 | uint8_t _pin; // Arduino pin connected to the button 28 | boolean _activeHigh; // Type of button: Active-low = 0 or active-high = 1 29 | boolean _btnState; // Current appearant button state 30 | boolean _lastState; // previous button reading 31 | int _clickCount; // Number of button clicks within multiclickTime milliseconds 32 | long _lastBounceTime; // the last time the button input pin was toggled, due to noise or a press 33 | }; 34 | 35 | #endif 36 | 37 | -------------------------------------------------------------------------------- /libraries/src/FreeRam.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * FreeRam.cpp 3 | * 4 | * Created on: 210.11.2016 5 | * Author: Thorsten Pferdekaemper thorsten@pferdekaemper.com 6 | */ 7 | 8 | #include "FreeRam.h" 9 | 10 | int freeRam () 11 | { 12 | #if defined (__AVR__) 13 | extern int __heap_start, *__brkval; 14 | int v; 15 | return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 16 | #elif defined (ARDUINO_ARCH_RP2040) 17 | extern char __StackLimit, __bss_end__; 18 | struct mallinfo mi = mallinfo(); 19 | return (int)((uint32_t)(&__StackLimit - &__bss_end__) - mi.uordblks); 20 | #else 21 | return -1; 22 | #endif 23 | }; 24 | -------------------------------------------------------------------------------- /libraries/src/FreeRam.h: -------------------------------------------------------------------------------- 1 | /* 2 | * FreeRam.h 3 | * 4 | * Created on: 21.11.2016 5 | * Author: Thorsten Pferdekaemper 6 | */ 7 | 8 | #ifndef FreeRam_h 9 | #define FreeRam_h 10 | 11 | #include "Arduino.h" 12 | 13 | #if defined (ARDUINO_ARCH_RP2040) 14 | #include 15 | #endif 16 | 17 | int freeRam (); 18 | 19 | #endif /* FreeRam_h */ 20 | -------------------------------------------------------------------------------- /libraries/src/HBWAnalogIn.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * HBWAnalogIn.cpp 3 | * 4 | * analog input channel, max. 16 bit reading 5 | * 6 | * Updated: 17.05.2020 7 | * www.loetmeister.de 8 | * 9 | */ 10 | 11 | #include "HBWAnalogIn.h" 12 | 13 | // Class HBWAnalogIn 14 | HBWAnalogIn::HBWAnalogIn(uint8_t _pin, hbw_config_analog_in* _config) { 15 | pin = _pin; 16 | config = _config; 17 | lastActionTime = 0; 18 | nextActionDelay = SAMPLE_INTERVAL *2; // initial dealy 19 | currentValue = 0; 20 | lastSendValue = 0; 21 | lastSentTime = 0; 22 | analogRead(pin); 23 | }; 24 | 25 | 26 | // channel specific settings or defaults 27 | void HBWAnalogIn::afterReadConfig() { 28 | if (config->update_interval == 0xFF) config->update_interval = DEFAULT_UPDATE_INTERVAL/10; 29 | if (config->send_delta_value == 0xFF) config->send_delta_value = 100; // delta as raw ADC value (consider factor in XML!) 30 | if (config->send_max_interval == 0xFFFF) config->send_max_interval = DEFAULT_UPDATE_INTERVAL *2; // not faster than update interval 31 | if (config->send_min_interval == 0xFF) config->send_min_interval = 30 /10; // 30 seconds (send_min_interval has 10 seconds stepping) 32 | }; 33 | 34 | 35 | /* standard public function - returns length of data array. Data array contains current channel reading */ 36 | uint8_t HBWAnalogIn::get(uint8_t* data) { 37 | 38 | // MSB first 39 | *data++ = (currentValue >> 8); 40 | *data = currentValue & 0xFF; 41 | return 2; 42 | }; 43 | 44 | 45 | /* standard public function - called by main loop for every channel in sequential order */ 46 | void HBWAnalogIn::loop(HBWDevice* device, uint8_t channel) { 47 | 48 | if (config->update_interval == 0) { // skip disabled channels 49 | currentValue = 0; 50 | lastSendValue = 0; 51 | return; 52 | } 53 | 54 | unsigned long now = millis(); 55 | 56 | // check if some values have to be send - do not send before min interval 57 | if (config->send_min_interval && now - lastSentTime <= (uint32_t)config->send_min_interval * 10000) return; 58 | if ((config->send_max_interval && now - lastSentTime >= (uint32_t)config->send_max_interval * 1000) || 59 | (config->send_delta_value && abs( currentValue - lastSendValue ) >= (unsigned int)config->send_delta_value)) { 60 | // send new value 61 | static uint8_t level[2]; 62 | get(level); 63 | if (device->sendInfoMessage(channel, sizeof(level), level) != HBWDevice::BUS_BUSY) { 64 | lastSendValue = currentValue; // store last value only on success 65 | } 66 | lastSentTime = now; // if send failed, next try will be on send_max_interval or send_min_interval in case the value is still different (send_delta_value) 67 | 68 | #ifdef DEBUG_OUTPUT 69 | hbwdebug(F("adc-ch: ")); hbwdebug(channel); 70 | hbwdebug(F(" sent: ")); hbwdebug(lastSendValue); lastSendValue == currentValue ? hbwdebug(F(" SUCCESS!\n")) : hbwdebug(F(" FAILED!\n")); 71 | #endif 72 | } 73 | 74 | if (now - lastActionTime < ((uint32_t)nextActionDelay *1000)) return; // quit if wait time not yet passed 75 | 76 | nextActionDelay = SAMPLE_INTERVAL; 77 | #define MAX_SAMPLES 3 // update "buffer" array definition, when changing this 78 | static uint16_t buffer[MAX_SAMPLES] = {0, 0, 0}; 79 | static uint8_t nextIndex = 0; 80 | 81 | buffer[nextIndex++] = analogRead(pin); 82 | lastActionTime = now; 83 | 84 | if (nextIndex >= MAX_SAMPLES) { 85 | nextIndex = 0; 86 | uint32_t sum = 0; 87 | uint8_t i = MAX_SAMPLES; 88 | do { 89 | sum += buffer[--i]; 90 | } 91 | while (i); 92 | 93 | currentValue = sum / MAX_SAMPLES; 94 | // "sleep" until next update 95 | nextActionDelay = config->update_interval *10; 96 | 97 | #ifdef DEBUG_OUTPUT 98 | hbwdebug(F("adc-ch:")); hbwdebug(channel); hbwdebug(F(" measured:")); hbwdebug(currentValue); hbwdebug(F("\n")); 99 | #endif 100 | } 101 | }; 102 | 103 | -------------------------------------------------------------------------------- /libraries/src/HBWAnalogIn.h: -------------------------------------------------------------------------------- 1 | /* 2 | * HBWAnalogIn.h 3 | * 4 | * analog input channel, max. 16 bit reading 5 | * 6 | * www.loetmeister.de 7 | * 8 | */ 9 | 10 | #ifndef HBWAnalogIn_h 11 | #define HBWAnalogIn_h 12 | 13 | #include 14 | #include "HBWired.h" 15 | 16 | 17 | //#define DEBUG_OUTPUT // extra debug output on serial/USB 18 | 19 | #define SAMPLE_INTERVAL 3 // seconds * 3 samples 20 | #define DEFAULT_UPDATE_INTERVAL 300 // seconds 21 | 22 | // address step 6 23 | struct hbw_config_analog_in { 24 | uint8_t send_delta_value; // Differenz des Messwerts, ab dem gesendet wird 25 | uint16_t send_max_interval; // Maximum-Sendeintervall 26 | uint8_t send_min_interval; // Minimum-Sendeintervall (factor 10, range 10 to 2540 seconds) 27 | uint8_t update_interval; // factor 10, range 10 to 2540 seconds //TODO: 10 seconds stepping is ok? 28 | uint8_t dummy; 29 | }; 30 | 31 | 32 | // Class HBWAnalogIn 33 | class HBWAnalogIn : public HBWChannel { 34 | public: 35 | HBWAnalogIn(uint8_t _pin, hbw_config_analog_in* _config); 36 | virtual uint8_t get(uint8_t* data); 37 | virtual void loop(HBWDevice*, uint8_t channel); 38 | virtual void afterReadConfig(); 39 | 40 | private: 41 | uint8_t pin; // Pin 42 | hbw_config_analog_in* config; 43 | uint32_t lastActionTime; 44 | uint16_t nextActionDelay; 45 | uint16_t currentValue; // store last result (average) 46 | uint16_t lastSendValue; // result that has been send (average) 47 | uint32_t lastSentTime; // last time of successful send 48 | }; 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /libraries/src/HBWBlind.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** HBWBlind 3 | ** 4 | ** Rolladenaktor mit Richtungs und Aktiv Relais pro Kanal 5 | ** (Position offen: 100%, geschlossen 0%) 6 | ** 7 | ** Infos: http://loetmeister.de/Elektronik/homematic/index.htm#modules 8 | ** Vorlage: https://github.com/loetmeister/HM485-Lib/tree/markus/HBW-LC-Bl4 9 | ** 10 | */ 11 | 12 | #ifndef HBWBlind_h 13 | #define HBWBlind_h 14 | 15 | #include "HBWired.h" 16 | 17 | //#define DEBUG // enable per channel class 18 | 19 | /********************************/ 20 | /* Config der Rollo-Steuerung: */ 21 | /********************************/ 22 | 23 | #define BL_POS_UNKNOWN 1 // Position on device reset / unknown position (1 == 0.5%) 24 | 25 | #define ON HIGH // Möglichkeit für invertierte Logik 26 | #define OFF LOW 27 | #define UP LOW // "Richtungs-Relais" 28 | #define DOWN HIGH 29 | #define BLIND_WAIT_TIME 100 // Wartezeit [ms] zwischen Ansteuerung des "Richtungs-Relais" und des "Ein-/Aus-Relais" (Bei Richtungswechsel 8-fache Wartezeit) 30 | #define BLIND_OFFSET_TIME 1000 // Zeit [ms], die beim Anfahren der Endlagen auf die berechnete Zeit addiert wird, um die Endlagen wirklich sicher zu erreichen 31 | 32 | 33 | /* here comes the code... */ 34 | 35 | // config of blind channel, address step 7 36 | struct hbw_config_blind { 37 | byte logging:1; // 0x07:0 0x0E 0x15 0x1C 38 | // byte :7; // 0x07:1-7 0x0E 39 | byte blindMotorDelay:7; // Anlaufzeit (Verzögerung bis zur Bewegung, nachdem der Motor Spannung erhalten hat) 40 | unsigned char blindTimeChangeOver; // 0x08 0x0F 0x16 0x1D - Zulässige Laufzeit ohne die Position zu ändern (erlaubt Stellwinkel von Lamellen zu ändern) 41 | unsigned char blindReferenceRunCounter; // 0x09 0x10 0x17 0x1E 42 | unsigned int blindTimeBottomTop; // 0x0A 0x11 0x18 0x1F 43 | unsigned int blindTimeTopBottom; // 0x0C 0x13 0x1A 0x21 44 | }; 45 | 46 | 47 | // new class for blinds 48 | class HBWChanBl : public HBWChannel { 49 | public: 50 | HBWChanBl(uint8_t _blindDir, uint8_t _blindAct, hbw_config_blind* _config); 51 | virtual uint8_t get(uint8_t* data); 52 | virtual void loop(HBWDevice*, uint8_t channel); 53 | virtual void set(HBWDevice*, uint8_t length, uint8_t const * const data); 54 | virtual void afterReadConfig(); 55 | 56 | private: 57 | enum { 58 | BL_STATE_STOP, 59 | BL_STATE_RELAIS_OFF, 60 | BL_STATE_WAIT, 61 | BL_STATE_TURN_AROUND, 62 | BL_STATE_MOVE, 63 | BL_STATE_SWITCH_DIRECTION 64 | }; 65 | 66 | void getCurrentPosition(); 67 | uint8_t blindDir; // direction relay 68 | uint8_t blindAct; // activity relay 69 | hbw_config_blind* config; 70 | 71 | byte blindNextState; 72 | byte blindCurrentState; 73 | byte blindPositionRequested; 74 | byte blindPositionRequestedSave; 75 | byte blindPositionActual; 76 | byte blindPositionLast; 77 | byte blindAngleActual; 78 | byte blindRunCounter; 79 | bool blindDirection; 80 | bool blindForceNextState; 81 | bool blindPositionKnown; 82 | bool blindSearchingForRefPosition; 83 | unsigned int blindNextStateDelayTime; 84 | unsigned long blindTimeStart; 85 | unsigned long blindTimeLastAction; 86 | 87 | uint8_t lastKeyNum; 88 | }; 89 | 90 | #endif 91 | 92 | -------------------------------------------------------------------------------- /libraries/src/HBWDimBacklight.h: -------------------------------------------------------------------------------- 1 | /* 2 | * HBWDimBacklight.h 3 | * 4 | * Created on: 16.07.2020 5 | * loetmeister.de 6 | * No commercial use! 7 | * 8 | * Dimmable backlight for displays or other ilumination 9 | * Set level 0..100%, auto_brightness & auto_off (1..17 minutes) 10 | * 11 | */ 12 | 13 | #ifndef HBWDIMMERSIMPLE_H_ 14 | #define HBWDIMMERSIMPLE_H_ 15 | 16 | 17 | #include "HBWired.h" 18 | 19 | 20 | #define DEBUG_OUTPUT // debug output on serial/USB 21 | 22 | 23 | // config of Display backlight (dimmer) channel, address step 2 24 | struct hbw_config_dim_backlight { 25 | uint8_t startup:1; // initial state, 1=ON 26 | uint8_t auto_brightness:1; // default 1=auto_brightness enabled 27 | uint8_t auto_off:4; // 1..15 minutes standby delay. 0 = always on ( 0 = "special value", NOT_USED) 28 | uint8_t :2; //fillup 29 | uint8_t dummy; 30 | }; 31 | 32 | 33 | // dimmer channel for display backlight (or overall brightness, e.g. for OLED?) 34 | // Class HBWDimBacklight 35 | class HBWDimBacklight : public HBWChannel { 36 | public: 37 | // HBWDimBacklight(hbw_config_dim_backlight* _config, uint8_t _backlight_pin, HBWChannel* _brightnessChan = NULL); 38 | HBWDimBacklight(hbw_config_dim_backlight* _config, uint8_t _backlight_pin, uint8_t _photoresistor_pin = NOT_A_PIN); 39 | virtual void loop(HBWDevice*, uint8_t channel); 40 | virtual uint8_t get(uint8_t* data); 41 | virtual void set(HBWDevice*, uint8_t length, uint8_t const * const data); 42 | 43 | static boolean displayWakeUp; // allow other channels to "wake up" the backlight 44 | 45 | private: 46 | hbw_config_dim_backlight* config; 47 | uint8_t backlightPin; // (PWM!) pin for backlight 48 | uint8_t photoresistorPin; // light resistor (mabye not used == NOT_A_PIN) - pin must be ADC input! 49 | uint8_t brightness; // read ADC and save average here 50 | // HBWChannel* brightnessChan; 51 | uint8_t currentValue; // current dimmer level (0...200 -> 0...100%) 52 | uint32_t backlightLastUpdate; // last time of update 53 | uint32_t powerOnTime; 54 | uint8_t lastKeyNum; 55 | boolean initDone; 56 | 57 | static const uint32_t BACKLIGHT_UPDATE_INTERVAL = 1660; 58 | 59 | // TODO: add notify/logging? Not really needed, should be disabled in auto_brightness mode anyway 60 | }; 61 | 62 | 63 | #endif /* HBWDIMMERSIMPLE_H_ */ 64 | -------------------------------------------------------------------------------- /libraries/src/HBWKey.h: -------------------------------------------------------------------------------- 1 | #ifndef HBWKey_h 2 | #define HBWKey_h 3 | 4 | #include 5 | #include "HBWired.h" 6 | 7 | 8 | //#define DEBUG_OUTPUT 9 | 10 | /* possible input types */ 11 | // DOORSENSOR > sends a short KeyEvent on HIGH and long KeyEvent on LOW input level changes 12 | // MOTIONSENSOR > sends a short KeyEvent for raising or falling edge - not both 13 | // SWITCH > sends a short KeyEvent, each time the input (e.g. wall switch) changes the polarity 14 | // PUSHBUTTON > sends a short KeyEvent on short press and (repeated) long KeyEvent on long press 15 | 16 | #define ENABLE_SENSOR_STATE // allow to query key channels as SENSOR (returns DOOR_SENSOR.STATE - open/closed) 17 | 18 | // config, address step 2 19 | struct hbw_config_key { 20 | uint8_t n_input_locked:1; // 0x07:0 0=LOCKED, 1=UNLOCKED 21 | uint8_t n_inverted:1; // 0x07:1 0=inverted, 1=not inverted 22 | uint8_t pullup:1; // 0x07:2 // TODO: needed....? 23 | uint8_t input_type:2; // 0x07:3-4 3=PUSHBUTTON (default), 2=SWITCH, 1=MOTIONSENSOR, 0=DOORSENSOR 24 | uint8_t :3; // 0x07:5-7 25 | uint8_t long_press_time; // 0x08 26 | }; 27 | 28 | 29 | // Class HBWKey 30 | class HBWKey : public HBWChannel { 31 | public: 32 | HBWKey(uint8_t _pin, hbw_config_key* _config, boolean _activeHigh = false); 33 | virtual void loop(HBWDevice*, uint8_t channel); 34 | virtual uint8_t get(uint8_t* data); 35 | virtual void afterReadConfig(); 36 | 37 | enum InputType 38 | { // below values have to match INPUT_TYPE in XML! 39 | DOORSENSOR = 0, 40 | MOTIONSENSOR, 41 | SWITCH, 42 | PUSHBUTTON 43 | }; 44 | 45 | private: 46 | uint8_t pin; // Pin 47 | uint32_t keyPressedMillis; // Zeit, zu der die Taste gedrueckt wurde (fuer's Entprellen) 48 | uint32_t lastSentLong; // Zeit, zu der das letzte Mal longPress gesendet wurde 49 | uint8_t keyPressNum; 50 | hbw_config_key* config; 51 | boolean activeHigh; // activeHigh=true -> input active high, else active low 52 | 53 | inline boolean readInput() { 54 | boolean reading = (digitalRead(pin) ^ !config->n_inverted); 55 | return (activeHigh ^ reading); 56 | } 57 | 58 | static const uint32_t KEY_DEBOUNCE_TIME = 85; // ms 59 | static const uint32_t SWITCH_DEBOUNCE_TIME = 135; // ms 60 | // static const uint32_t DOORSENSOR_DEBOUNCE_TIME = 210; // ms --> use long_press_time 300 ms min value 61 | }; 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /libraries/src/HBWLinkBlindSimple.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ** HBWLinkBlindSimple 3 | ** 4 | ** Einfache direkte Verknuepfung (Peering), zu Schaltausgaengen 5 | ** Ein Link-Objekt steht immer fuer alle (direkt aufeinander folgenden) Verknuepfungen 6 | ** des entsprechenden Typs. 7 | ** 8 | */ 9 | 10 | #include "HBWLinkBlindSimple.h" 11 | -------------------------------------------------------------------------------- /libraries/src/HBWLinkBlindSimple.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** HBWLinkBlindSimple 3 | ** 4 | ** Einfache direkte Verknuepfung (Peering), zu Rolladenaktor 5 | ** Ein Link-Objekt steht immer fuer alle (direkt aufeinander folgenden) Verknuepfungen 6 | ** des entsprechenden Typs. 7 | ** 8 | */ 9 | 10 | #ifndef HBWLinkBlindSimple_h 11 | #define HBWLinkBlindSimple_h 12 | 13 | #include "HBWired.h" 14 | 15 | 16 | // need to match (default) frame definition in XML: 17 | #define SET_BLIND_TOGGLE 255 18 | #define SET_BLIND_STOP 201 19 | #define SET_BLIND_OPEN 200 20 | #define SET_BLIND_CLOSE 0 21 | 22 | 23 | template 24 | class HBWLinkBlindSimple : public HBWLinkReceiver { 25 | public: 26 | HBWLinkBlindSimple(); 27 | void receiveKeyEvent(HBWDevice* device, uint32_t senderAddress, uint8_t senderChannel, 28 | uint8_t targetChannel, uint8_t keyPressNum, boolean longPress); 29 | private: 30 | uint32_t lastSenderAddress; 31 | uint8_t lastSenderChannel; 32 | 33 | static const uint8_t EEPROM_SIZE = 9; // "address_step" in XML 34 | static const uint8_t NUM_PEER_PARAMS = 1; // number of bytes for long and short peering action each (without address and channel) 35 | }; 36 | 37 | #include "HBWLinkBlindSimple.hpp" 38 | #endif 39 | -------------------------------------------------------------------------------- /libraries/src/HBWLinkBlindSimple.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | ** HBWLinkBlindSimple 3 | ** 4 | ** Einfache direkte Verknuepfung (Peering), zu Schaltausgaengen 5 | ** Ein Link-Objekt steht immer fuer alle (direkt aufeinander folgenden) Verknuepfungen 6 | ** des entsprechenden Typs. 7 | ** 8 | */ 9 | 10 | 11 | template 12 | HBWLinkBlindSimple::HBWLinkBlindSimple() { 13 | } 14 | 15 | 16 | // processKeyEvent wird aufgerufen, wenn ein Tastendruck empfangen wurde 17 | // TODO: von wem aufgerufen? Direkt von der Tasten-Implementierung oder vom Device? 18 | // wahrscheinlich besser vom Device ueber sendKeyEvent 19 | // TODO: Der Beginn aller Verknuepfungen ist gleich. Eigentlich koennte man 20 | // das meiste in einer gemeinsamen Basisklasse abhandeln 21 | template 22 | void HBWLinkBlindSimple::receiveKeyEvent(HBWDevice* device, uint32_t senderAddress, uint8_t senderChannel, 23 | uint8_t targetChannel, uint8_t keyPressNum, boolean longPress) { 24 | 25 | uint32_t sndAddrEEPROM; 26 | uint8_t channelEEPROM; 27 | uint8_t actionType; 28 | uint8_t data[NUM_PEER_PARAMS +2]; // store all peer parameter (use extra element for keyPressNum & sameLastSender) 29 | 30 | data[NUM_PEER_PARAMS] = keyPressNum; 31 | data[NUM_PEER_PARAMS +1] = false; 32 | 33 | if (senderAddress == lastSenderAddress && senderChannel == lastSenderChannel) { 34 | data[NUM_PEER_PARAMS +1] = true; // true, as this was the same sender (source device & channel) - sameLastSender 35 | } 36 | lastSenderAddress = senderAddress; 37 | lastSenderChannel = senderChannel; 38 | 39 | // read what to do from EEPROM 40 | for(byte i = 0; i < numLinks; i++) { 41 | device->readEEPROM(&sndAddrEEPROM, eepromStart + EEPROM_SIZE * i, 4, true); 42 | // TODO: is the following really ok? 43 | // it reads to all links, even if none is set 44 | if(sndAddrEEPROM == 0xFFFFFFFF) continue; 45 | if(sndAddrEEPROM != senderAddress) continue; 46 | // compare sender channel 47 | device->readEEPROM(&channelEEPROM, eepromStart + EEPROM_SIZE * i + 4, 1); 48 | if(channelEEPROM != senderChannel) continue; 49 | // compare target channel 50 | device->readEEPROM(&channelEEPROM, eepromStart + EEPROM_SIZE * i + 5, 1); 51 | if(channelEEPROM != targetChannel) continue; 52 | // ok, we have found a match 53 | // read actionType 54 | device->readEEPROM(&actionType, eepromStart + EEPROM_SIZE * i + 6, 1); 55 | // differs for short and long 56 | if (longPress) { 57 | actionType = (actionType >> 3) & 0b00000111; 58 | device->readEEPROM(&data, eepromStart + EEPROM_SIZE * i + 8, 1); 59 | } 60 | else { 61 | actionType &= 0b00000111; 62 | device->readEEPROM(&data, eepromStart + EEPROM_SIZE * i + 7, 1); 63 | } 64 | // we can have 65 | switch(actionType) { 66 | // 0 -> OPEN 67 | case 0: data[0] = SET_BLIND_OPEN; 68 | break; 69 | // 1 -> STOP 70 | case 1: data[0] = SET_BLIND_STOP; 71 | break; 72 | // 2 -> CLOSE 73 | case 2: data[0] = SET_BLIND_CLOSE; 74 | break; 75 | // 3 -> TOGGLE (default) 76 | case 3: data[0] = SET_BLIND_TOGGLE; 77 | break; 78 | // 4 -> LEVEL 79 | case 4: { asm ("nop"); } // target level already stored in "data" - nothing to do... 80 | break; 81 | // 5 -> INACTIVE 82 | case 5: continue; 83 | }; 84 | device->set(targetChannel, sizeof(data), data); // channel, data length, data 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /libraries/src/HBWLinkDimmerAdvanced.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ** HBWLinkDimmerAdvanced 3 | ** 4 | ** Direkte Verknuepfung (Peering), zu Schaltausgaengen 5 | ** Ein Link-Objekt steht immer fuer alle (direkt aufeinander folgenden) Verknuepfungen 6 | ** des entsprechenden Typs. 7 | ** 8 | ** http://loetmeister.de/Elektronik/homematic/ 9 | */ 10 | 11 | #include "HBWLinkDimmerAdvanced.h" 12 | -------------------------------------------------------------------------------- /libraries/src/HBWLinkDimmerAdvanced.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** HBWLinkDimmerAdvanced 3 | ** 4 | ** Direkte Verknuepfung (Peering), zu Schaltausgaengen 5 | ** Ein Link-Objekt steht immer fuer alle (direkt aufeinander folgenden) Verknuepfungen 6 | ** des entsprechenden Typs. 7 | ** 8 | ** http://loetmeister.de/Elektronik/homematic/ 9 | */ 10 | 11 | #ifndef HBWLinkDimmerAdvanced_h 12 | #define HBWLinkDimmerAdvanced_h 13 | 14 | #include "HBWired.h" 15 | 16 | 17 | template 18 | class HBWLinkDimmerAdvanced : public HBWLinkReceiver { 19 | public: 20 | HBWLinkDimmerAdvanced(); 21 | void receiveKeyEvent(HBWDevice* device, uint32_t senderAddress, uint8_t senderChannel, 22 | uint8_t targetChannel, uint8_t keyPressNum, boolean longPress); 23 | 24 | private: 25 | uint32_t lastSenderAddress; 26 | uint8_t lastSenderChannel; 27 | 28 | static const uint8_t EEPROM_SIZE = 42; // "address_step" in XML 29 | static const uint8_t NUM_PEER_PARAMS = 18; // number of bytes for long and short peering action each (without address and channel) 30 | }; 31 | 32 | #include "HBWLinkDimmerAdvanced.hpp" 33 | #endif 34 | -------------------------------------------------------------------------------- /libraries/src/HBWLinkDimmerAdvanced.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | ** HBWLinkDimmerAdvanced 3 | ** 4 | ** Direkte Verknuepfung (Peering), zu Schaltausgaengen 5 | ** Ein Link-Objekt steht immer fuer alle (direkt aufeinander folgenden) Verknuepfungen 6 | ** des entsprechenden Typs. 7 | ** 8 | ** http://loetmeister.de/Elektronik/homematic/ 9 | */ 10 | 11 | 12 | template 13 | HBWLinkDimmerAdvanced::HBWLinkDimmerAdvanced() { 14 | } 15 | 16 | 17 | // receiveKeyEvent wird aufgerufen, wenn ein Tastendruck empfangen wurde 18 | // TODO: Der Beginn aller Verknuepfungen ist gleich. Eigentlich koennte man 19 | // das meiste in einer gemeinsamen Basisklasse abhandeln 20 | template 21 | void HBWLinkDimmerAdvanced::receiveKeyEvent(HBWDevice* device, uint32_t senderAddress, uint8_t senderChannel, 22 | uint8_t targetChannel, uint8_t keyPressNum, boolean longPress) { 23 | 24 | uint32_t sndAddrEEPROM; 25 | uint8_t channelEEPROM; 26 | uint8_t actionType; 27 | uint8_t data[NUM_PEER_PARAMS +2]; // store all peer parameter (use extra element for keyPressNum & sameLastSender) 28 | 29 | data[NUM_PEER_PARAMS] = keyPressNum; 30 | data[NUM_PEER_PARAMS +1] = false; 31 | 32 | if (senderAddress == lastSenderAddress && senderChannel == lastSenderChannel) { 33 | data[NUM_PEER_PARAMS +1] = true; // true, as this was the same sender (source device & channel) - sameLastSender 34 | } 35 | lastSenderAddress = senderAddress; 36 | lastSenderChannel = senderChannel; 37 | 38 | // read what to do from EEPROM 39 | for(byte i = 0; i < numLinks; i++) { 40 | device->readEEPROM(&sndAddrEEPROM, eepromStart + EEPROM_SIZE * i, 4, true); 41 | // TODO: is the following really ok? 42 | // it reads to all links, even if none is set 43 | if(sndAddrEEPROM == 0xFFFFFFFF) continue; 44 | if(sndAddrEEPROM != senderAddress) continue; 45 | // compare sender channel 46 | device->readEEPROM(&channelEEPROM, eepromStart + EEPROM_SIZE * i + 4, 1); 47 | if(channelEEPROM != senderChannel) continue; 48 | // compare target channel 49 | device->readEEPROM(&channelEEPROM, eepromStart + EEPROM_SIZE * i + 5, 1); 50 | if(channelEEPROM != targetChannel) continue; 51 | // ok, we have found a match 52 | if (!longPress) { // differs for short and long 53 | device->readEEPROM(&actionType, eepromStart + EEPROM_SIZE * i + 6, 1); // read shortPress actionType 54 | if (actionType & 0b00001111) { // SHORT_ACTION_TYPE, ACTIVE 55 | // when active, read all other values and call channel set() 56 | device->readEEPROM(&data, eepromStart + EEPROM_SIZE * i + 6, NUM_PEER_PARAMS); // read all parameters (must be consecutive) 57 | // + 6 // SHORT_ACTION_TYPE 58 | // + 7 // SHORT_ONDELAY_TIME 59 | // + 8 // SHORT_ON_TIME 60 | // + 9 // SHORT_OFFDELAY_TIME 61 | // + 10 // SHORT_OFF_TIME 62 | // + 11 // SHORT_OFF_LEVEL 63 | // + 12 // SHORT_ON_MIN_LEVEL 64 | // + 13 // SHORT_ON_LEVEL 65 | // + 14 // SHORT_ONDELAY_MODE, SHORT_ON_LEVEL_PRIO, SHORT_OFFDELAY_BLINK, SHORT_RAMP_START_STEP 66 | // + 15 // SHORT_RAMPON_TIME 67 | // + 16 // SHORT_RAMPOFF_TIME 68 | // + 17 // SHORT_DIM_MIN_LEVEL 69 | // + 18 // SHORT_DIM_MAX_LEVEL 70 | // + 19 // SHORT_DIM_STEP, SHORT_OFFDELAY_STEP 71 | // + 20 // SHORT_OFFDELAY_NEWTIME, SHORT_OFFDELAY_OLDTIME 72 | // + 21, 22, 23 // SHORT_JT_* table 73 | device->set(targetChannel, sizeof(data), data); // channel, data length, data 74 | } 75 | } 76 | // read specific long action eeprom section 77 | else { 78 | device->readEEPROM(&actionType, eepromStart + EEPROM_SIZE * i + 6 + NUM_PEER_PARAMS, 1); // read longPress actionType 79 | if (actionType & 0b00001111) { // LONG_ACTION_TYPE, ACTIVE 80 | // when active, read all other values and call channel set() 81 | device->readEEPROM(&data, eepromStart + EEPROM_SIZE * i + 6 + NUM_PEER_PARAMS, NUM_PEER_PARAMS); // read all parameters (must be consecutive) 82 | // + 6+ NUM_PEER_PARAMS // LONG_ACTION_TYPE 83 | // + 7+ NUM_PEER_PARAMS // LONG_ONDELAY_TIME 84 | // ... and so on. Layout for LONG_* and SHORT_* must be the same 85 | device->set(targetChannel, sizeof(data), data); // channel, data length, data 86 | } 87 | } 88 | } 89 | } 90 | 91 | -------------------------------------------------------------------------------- /libraries/src/HBWLinkInfoEventActuator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ** HBWLinkInfoEventActuator 3 | ** 4 | ** Einfache direkte Verknuepfung (Peering), zu Schaltausgaengen 5 | ** Ein Link-Objekt steht immer fuer alle (direkt aufeinander folgenden) Verknuepfungen 6 | ** des entsprechenden Typs. 7 | ** 8 | */ 9 | 10 | #include "HBWLinkInfoEventActuator.h" 11 | -------------------------------------------------------------------------------- /libraries/src/HBWLinkInfoEventActuator.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** HBWLinkInfoEventActuator 3 | ** 4 | ** Einfache direkte Verknuepfung (Peering), zu Schaltausgaengen 5 | ** Ein Link-Objekt steht immer fuer alle (direkt aufeinander folgenden) Verknuepfungen 6 | ** des entsprechenden Typs. 7 | ** 8 | */ 9 | 10 | #ifndef HBWLinkInfoEventActuator_h 11 | #define HBWLinkInfoEventActuator_h 12 | 13 | #include "HBWired.h" 14 | 15 | 16 | template 17 | class HBWLinkInfoEventActuator : public HBWLinkReceiver { 18 | public: 19 | HBWLinkInfoEventActuator(); 20 | void receiveInfoEvent(HBWDevice* device, uint32_t senderAddress, uint8_t senderChannel, 21 | uint8_t targetChannel, uint8_t length, uint8_t const * const data); 22 | private: 23 | static const uint8_t EEPROM_SIZE = 7; // "address_step" in XML 24 | }; 25 | 26 | #include "HBWLinkInfoEventActuator.hpp" 27 | #endif 28 | -------------------------------------------------------------------------------- /libraries/src/HBWLinkInfoEventActuator.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | ** HBWLinkInfoEventActuator 3 | ** 4 | ** Einfache direkte Verknuepfung (Peering), zu Schaltausgaengen 5 | ** Ein Link-Objekt steht immer fuer alle (direkt aufeinander folgenden) Verknuepfungen 6 | ** des entsprechenden Typs. 7 | ** 8 | */ 9 | 10 | 11 | #ifdef Support_HBWLink_InfoEvent 12 | template 13 | HBWLinkInfoEventActuator::HBWLinkInfoEventActuator() { 14 | } 15 | 16 | 17 | // TODO: Der Beginn aller Verknuepfungen ist gleich. Eigentlich koennte man 18 | // das meiste in einer gemeinsamen Basisklasse abhandeln 19 | template 20 | void HBWLinkInfoEventActuator::receiveInfoEvent(HBWDevice* device, uint32_t senderAddress, uint8_t senderChannel, 21 | uint8_t targetChannel, uint8_t length, uint8_t const * const data) { 22 | 23 | uint32_t sndAddrEEPROM; 24 | uint8_t channelEEPROM; 25 | 26 | // read what to do from EEPROM 27 | for(byte i = 0; i < numLinks; i++) { 28 | device->readEEPROM(&sndAddrEEPROM, eepromStart + EEPROM_SIZE * i, 4, true); 29 | // TODO: is the following really ok? 30 | // it reads to all links, even if none is set 31 | if(sndAddrEEPROM == 0xFFFFFFFF) continue; 32 | if(sndAddrEEPROM != senderAddress) continue; 33 | // compare sender channel 34 | device->readEEPROM(&channelEEPROM, eepromStart + EEPROM_SIZE * i + 4, 1); 35 | if(channelEEPROM != senderChannel) continue; 36 | // compare target channel 37 | device->readEEPROM(&channelEEPROM, eepromStart + EEPROM_SIZE * i + 5, 1); 38 | if(channelEEPROM != targetChannel) continue; 39 | // ok, we have found a match 40 | 41 | 42 | device->setInfo(targetChannel, length, data); // channel, data length, data 43 | } 44 | } 45 | #endif 46 | -------------------------------------------------------------------------------- /libraries/src/HBWLinkInfoEventSensor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ** HBWLinkInfoEventSensor 3 | ** 4 | ** Einfache direkte Verknuepfung (Peering), vom Sensor ausgehend 5 | ** Ein Link-Objekt steht immer fuer alle (direkt aufeinander folgenden) Verknuepfungen 6 | ** des entsprechenden Typs. 7 | ** 8 | */ 9 | 10 | 11 | #include "HBWLinkInfoEventSensor.h" 12 | -------------------------------------------------------------------------------- /libraries/src/HBWLinkInfoEventSensor.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** HBWLinkInfoEventSensor 3 | ** 4 | ** Einfache direkte Verknuepfung (Peering), vom Sensor ausgehend 5 | ** Ein Link-Objekt steht immer fuer alle (direkt aufeinander folgenden) Verknuepfungen 6 | ** des entsprechenden Typs. 7 | ** 8 | */ 9 | 10 | 11 | #ifndef HBWLinkInfoEventSensor_h 12 | #define HBWLinkInfoEventSensor_h 13 | 14 | #include "HBWired.h" 15 | 16 | 17 | template 18 | class HBWLinkInfoEventSensor : public HBWLinkSender { 19 | public: 20 | HBWLinkInfoEventSensor(); 21 | void sendInfoEvent(HBWDevice* device, uint8_t srcChan, uint8_t length, uint8_t const * const data); 22 | private: 23 | static const uint8_t EEPROM_SIZE = 6; // "address_step" in XML 24 | }; 25 | 26 | #include "HBWLinkInfoEventSensor.hpp" 27 | #endif 28 | -------------------------------------------------------------------------------- /libraries/src/HBWLinkInfoEventSensor.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | ** HBWLinkInfoEventSensor 3 | ** 4 | ** Einfache direkte Verknuepfung (Peering), vom Sensor ausgehend 5 | ** Ein Link-Objekt steht immer fuer alle (direkt aufeinander folgenden) Verknuepfungen 6 | ** des entsprechenden Typs. 7 | ** 8 | */ 9 | 10 | 11 | #ifdef Support_HBWLink_InfoEvent 12 | template 13 | HBWLinkInfoEventSensor::HBWLinkInfoEventSensor() { 14 | } 15 | 16 | 17 | // TODO: Der Beginn aller Verknuepfungen ist gleich. Eigentlich koennte man 18 | // das meiste in einer gemeinsamen Basisklasse abhandeln 19 | template 20 | void HBWLinkInfoEventSensor::sendInfoEvent(HBWDevice* device, uint8_t srcChan, 21 | uint8_t length, uint8_t const * const data) { 22 | uint8_t channelEEPROM; 23 | uint32_t addrEEPROM; 24 | // care for peerings 25 | for(int i = 0; i < numLinks; i++) { 26 | // get channel number 27 | device->readEEPROM(&channelEEPROM, eepromStart + EEPROM_SIZE * i, 1); 28 | // valid peering? 29 | // TODO: Really like that? This always goes through all possible peerings 30 | if(channelEEPROM == 0xFF) continue; 31 | // channel is key? 32 | if(channelEEPROM != srcChan) continue; 33 | // get address and channel of actuator 34 | device->readEEPROM(&addrEEPROM, eepromStart + EEPROM_SIZE * i + 1, 4, true); 35 | device->readEEPROM(&channelEEPROM, eepromStart + EEPROM_SIZE * i +5, 1); 36 | // own address? -> internal peering 37 | if(addrEEPROM == device->getOwnAddress()) { 38 | device->receiveInfoEvent(addrEEPROM, srcChan, channelEEPROM, length, data); 39 | }else{ 40 | // external peering 41 | // TODO: If bus busy, then try to repeat. ...aber zuerst feststellen, wie das die Original-Module machen (bzw. hier einfach so lassen) 42 | /* byte result = */ 43 | device->sendInfoEvent(srcChan, length, data, addrEEPROM, channelEEPROM, !NEED_IDLE_BUS, PEER_SEND_RETRIES); // free/idle bus was checked before calling sendInfoEvent - by sending a broadcast message 44 | }; 45 | }; 46 | } 47 | #endif 48 | -------------------------------------------------------------------------------- /libraries/src/HBWLinkKey.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ** HBWLinkKey 3 | ** 4 | ** Einfache direkte Verknuepfung (Peering), vom Tastereingang ausgehend 5 | ** Ein Link-Objekt steht immer fuer alle (direkt aufeinander folgenden) Verknuepfungen 6 | ** des entsprechenden Typs. 7 | ** 8 | */ 9 | 10 | #include "HBWLinkKey.h" 11 | -------------------------------------------------------------------------------- /libraries/src/HBWLinkKey.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** HBWLinkKey 3 | ** 4 | ** Einfache direkte Verknuepfung (Peering), vom Tastereingang ausgehend 5 | ** Ein Link-Objekt steht immer fuer alle (direkt aufeinander folgenden) Verknuepfungen 6 | ** des entsprechenden Typs. 7 | ** 8 | */ 9 | 10 | 11 | #ifndef HBWLinkKey_h 12 | #define HBWLinkKey_h 13 | 14 | #include "HBWired.h" 15 | 16 | 17 | template 18 | class HBWLinkKey : public HBWLinkSender { 19 | public: 20 | HBWLinkKey(); 21 | void sendKeyEvent(HBWDevice* device, uint8_t srcChan, uint8_t keyPressNum, boolean longPress); 22 | private: 23 | static const uint8_t EEPROM_SIZE = 6; // "address_step" in XML 24 | }; 25 | 26 | #include "HBWLinkKey.hpp" 27 | #endif 28 | -------------------------------------------------------------------------------- /libraries/src/HBWLinkKey.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | ** HBWLinkKey 3 | ** 4 | ** Einfache direkte Verknuepfung (Peering), vom Tastereingang ausgehend 5 | ** Ein Link-Objekt steht immer fuer alle (direkt aufeinander folgenden) Verknuepfungen 6 | ** des entsprechenden Typs. 7 | ** 8 | */ 9 | 10 | 11 | template 12 | HBWLinkKey::HBWLinkKey() { 13 | } 14 | 15 | 16 | // keyPressed wird aufgerufen, wenn ein Tastendruck erkannt wurde 17 | // TODO: von wem? Direkt von der Tasten-Implementierung oder vom Device? 18 | // wahrscheinlich besser vom Device ueber sendKeyEvent 19 | // TODO: Der Beginn aller Verknuepfungen ist gleich. Eigentlich koennte man 20 | // das meiste in einer gemeinsamen Basisklasse abhandeln 21 | template 22 | void HBWLinkKey::sendKeyEvent(HBWDevice* device, uint8_t srcChan, 23 | uint8_t keyPressNum, boolean longPress) { 24 | uint8_t channelEEPROM; 25 | uint32_t addrEEPROM; 26 | // care for peerings 27 | for(int i = 0; i < numLinks; i++) { 28 | // get channel number 29 | device->readEEPROM(&channelEEPROM, eepromStart + EEPROM_SIZE * i, 1); 30 | // valid peering? 31 | // TODO: Really like that? This always goes through all possible peerings 32 | if(channelEEPROM == 0xFF) continue; 33 | // channel is key? 34 | if(channelEEPROM != srcChan) continue; 35 | // get address and channel of actuator 36 | device->readEEPROM(&addrEEPROM, eepromStart + EEPROM_SIZE * i + 1, 4, true); 37 | device->readEEPROM(&channelEEPROM, eepromStart + EEPROM_SIZE * i +5, 1); 38 | // own address? -> internal peering 39 | if(addrEEPROM == device->getOwnAddress()) { 40 | device->receiveKeyEvent(addrEEPROM, srcChan, channelEEPROM, keyPressNum, longPress); 41 | }else{ 42 | // external peering 43 | // TODO: If bus busy, then try to repeat. ...aber zuerst feststellen, wie das die Original-Module machen (bzw. hier einfach so lassen) 44 | /* byte result = */ 45 | device->sendKeyEvent(srcChan, keyPressNum, longPress, addrEEPROM, channelEEPROM, !NEED_IDLE_BUS, PEER_SEND_RETRIES); // free/idle bus was checked before calling sendKeyEvent - by sending a broadcast message 46 | }; 47 | }; 48 | } 49 | -------------------------------------------------------------------------------- /libraries/src/HBWLinkSwitchAdvanced.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ** HBWLinkSwitchAdvanced 3 | ** 4 | ** Direkte Verknuepfung (Peering), zu Schaltausgaengen 5 | ** Ein Link-Objekt steht immer fuer alle (direkt aufeinander folgenden) Verknuepfungen 6 | ** des entsprechenden Typs. 7 | ** 8 | ** http://loetmeister.de/Elektronik/homematic/ 9 | */ 10 | 11 | #include "HBWLinkSwitchAdvanced.h" 12 | -------------------------------------------------------------------------------- /libraries/src/HBWLinkSwitchAdvanced.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** HBWLinkSwitchAdvanced 3 | ** 4 | ** Direkte Verknuepfung (Peering), zu Schaltausgaengen 5 | ** Ein Link-Objekt steht immer fuer alle (direkt aufeinander folgenden) Verknuepfungen 6 | ** des entsprechenden Typs. 7 | ** 8 | ** http://loetmeister.de/Elektronik/homematic/ 9 | */ 10 | 11 | #ifndef HBWLinkSwitchAdvanced_h 12 | #define HBWLinkSwitchAdvanced_h 13 | 14 | #include "HBWired.h" 15 | 16 | 17 | template 18 | class HBWLinkSwitchAdvanced : public HBWLinkReceiver { 19 | public: 20 | HBWLinkSwitchAdvanced(); 21 | void receiveKeyEvent(HBWDevice* device, uint32_t senderAddress, uint8_t senderChannel, 22 | uint8_t targetChannel, uint8_t keyPressNum, boolean longPress); 23 | 24 | private: 25 | uint32_t lastSenderAddress; 26 | uint8_t lastSenderChannel; 27 | 28 | static const uint8_t EEPROM_SIZE = 20; // "address_step" in XML 29 | static const uint8_t NUM_PEER_PARAMS = 7; // number of bytes for long and short peering action each (without address and channel) 30 | }; 31 | 32 | #include "HBWLinkSwitchAdvanced.hpp" 33 | #endif 34 | -------------------------------------------------------------------------------- /libraries/src/HBWLinkSwitchAdvanced.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | ** HBWLinkSwitchAdvanced 3 | ** 4 | ** Direkte Verknuepfung (Peering), zu Schaltausgaengen 5 | ** Ein Link-Objekt steht immer fuer alle (direkt aufeinander folgenden) Verknuepfungen 6 | ** des entsprechenden Typs. 7 | ** 8 | ** http://loetmeister.de/Elektronik/homematic/ 9 | */ 10 | 11 | 12 | template 13 | HBWLinkSwitchAdvanced::HBWLinkSwitchAdvanced() { 14 | } 15 | 16 | 17 | // receiveKeyEvent wird aufgerufen, wenn ein Tastendruck empfangen wurde 18 | // TODO: Der Beginn aller Verknuepfungen ist gleich. Eigentlich koennte man 19 | // das meiste in einer gemeinsamen Basisklasse abhandeln 20 | template 21 | void HBWLinkSwitchAdvanced::receiveKeyEvent(HBWDevice* device, uint32_t senderAddress, uint8_t senderChannel, 22 | uint8_t targetChannel, uint8_t keyPressNum, boolean longPress) { 23 | 24 | uint32_t sndAddrEEPROM; 25 | uint8_t channelEEPROM; 26 | uint8_t actionType; 27 | uint8_t data[NUM_PEER_PARAMS +2]; // store all peer parameter (use extra element for keyPressNum & sameLastSender) 28 | 29 | data[NUM_PEER_PARAMS] = keyPressNum; 30 | data[NUM_PEER_PARAMS +1] = false; 31 | 32 | if (senderAddress == lastSenderAddress && senderChannel == lastSenderChannel) { 33 | data[NUM_PEER_PARAMS +1] = true; // true, as this was the same sender (source device & channel) - sameLastSender 34 | } 35 | lastSenderAddress = senderAddress; 36 | lastSenderChannel = senderChannel; 37 | 38 | // read what to do from EEPROM 39 | for(byte i = 0; i < numLinks; i++) { 40 | device->readEEPROM(&sndAddrEEPROM, eepromStart + EEPROM_SIZE * i, 4, true); 41 | // TODO: is the following really ok? 42 | // it reads to all links, even if none is set 43 | if(sndAddrEEPROM == 0xFFFFFFFF) continue; 44 | if(sndAddrEEPROM != senderAddress) continue; 45 | // compare sender channel 46 | device->readEEPROM(&channelEEPROM, eepromStart + EEPROM_SIZE * i + 4, 1); 47 | if(channelEEPROM != senderChannel) continue; 48 | // compare target channel 49 | device->readEEPROM(&channelEEPROM, eepromStart + EEPROM_SIZE * i + 5, 1); 50 | if(channelEEPROM != targetChannel) continue; 51 | // ok, we have found a match 52 | if (!longPress) { // differs for short and long 53 | device->readEEPROM(&actionType, eepromStart + EEPROM_SIZE * i + 6, 1); // read shortPress actionType 54 | if (actionType & 0b00001111) { // SHORT_ACTION_TYPE, ACTIVE 55 | // when active, read all other values and call channel set() 56 | device->readEEPROM(&data, eepromStart + EEPROM_SIZE * i + 6, NUM_PEER_PARAMS); // read all parameters (must be consecutive) 57 | // + 6 // SHORT_ACTION_TYPE 58 | // + 7 // SHORT_ONDELAY_TIME 59 | // + 8 // SHORT_ON_TIME 60 | // + 9 // SHORT_OFFDELAY_TIME 61 | // + 10 // SHORT_OFF_TIME 62 | // + 11, 12 // SHORT_JT_* table 63 | device->set(targetChannel, sizeof(data), data); // channel, data length, data 64 | } 65 | } 66 | // read specific long action eeprom section 67 | else { 68 | device->readEEPROM(&actionType, eepromStart + EEPROM_SIZE * i + 6 + NUM_PEER_PARAMS, 1); // read longPress actionType 69 | if (actionType & 0b00001111) { // LONG_ACTION_TYPE, ACTIVE 70 | // when active, read all other values and call channel set() 71 | device->readEEPROM(&data, eepromStart + EEPROM_SIZE * i + 6 + NUM_PEER_PARAMS, NUM_PEER_PARAMS); // read all parameters (must be consecutive) 72 | device->set(targetChannel, sizeof(data), data); // channel, data length, data 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /libraries/src/HBWLinkSwitchSimple.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ** HBWLinkSwitchSimple 3 | ** 4 | ** Einfache direkte Verknuepfung (Peering), zu Schaltausgaengen 5 | ** Ein Link-Objekt steht immer fuer alle (direkt aufeinander folgenden) Verknuepfungen 6 | ** des entsprechenden Typs. 7 | ** 8 | */ 9 | 10 | #include "HBWLinkSwitchSimple.h" 11 | -------------------------------------------------------------------------------- /libraries/src/HBWLinkSwitchSimple.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** HBWLinkSwitchSimple 3 | ** 4 | ** Einfache direkte Verknuepfung (Peering), zu Schaltausgaengen 5 | ** Ein Link-Objekt steht immer fuer alle (direkt aufeinander folgenden) Verknuepfungen 6 | ** des entsprechenden Typs. 7 | ** 8 | */ 9 | 10 | #ifndef HBWLinkSwitchSimple_h 11 | #define HBWLinkSwitchSimple_h 12 | 13 | #include "HBWired.h" 14 | 15 | 16 | template 17 | class HBWLinkSwitchSimple : public HBWLinkReceiver { 18 | public: 19 | HBWLinkSwitchSimple(); 20 | void receiveKeyEvent(HBWDevice* device, uint32_t senderAddress, uint8_t senderChannel, 21 | uint8_t targetChannel, uint8_t keyPressNum, boolean longPress); 22 | private: 23 | static const uint8_t EEPROM_SIZE = 7; // "address_step" in XML 24 | }; 25 | 26 | #include "HBWLinkSwitchSimple.hpp" 27 | #endif 28 | -------------------------------------------------------------------------------- /libraries/src/HBWLinkSwitchSimple.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | ** HBWLinkSwitchSimple 3 | ** 4 | ** Einfache direkte Verknuepfung (Peering), zu Schaltausgaengen 5 | ** Ein Link-Objekt steht immer fuer alle (direkt aufeinander folgenden) Verknuepfungen 6 | ** des entsprechenden Typs. 7 | ** 8 | */ 9 | 10 | 11 | template 12 | HBWLinkSwitchSimple::HBWLinkSwitchSimple() { 13 | } 14 | 15 | 16 | // processKeyEvent wird aufgerufen, wenn ein Tastendruck empfangen wurde 17 | // TODO: von wem aufgerufen? Direkt von der Tasten-Implementierung oder vom Device? 18 | // wahrscheinlich besser vom Device ueber sendKeyEvent 19 | // TODO: Der Beginn aller Verknuepfungen ist gleich. Eigentlich koennte man 20 | // das meiste in einer gemeinsamen Basisklasse abhandeln 21 | template 22 | void HBWLinkSwitchSimple::receiveKeyEvent(HBWDevice* device, uint32_t senderAddress, uint8_t senderChannel, 23 | uint8_t targetChannel, uint8_t keyPressNum, boolean longPress) { 24 | 25 | uint32_t sndAddrEEPROM; 26 | uint8_t channelEEPROM; 27 | uint8_t actionType; 28 | // read what to do from EEPROM 29 | for(byte i = 0; i < numLinks; i++) { 30 | device->readEEPROM(&sndAddrEEPROM, eepromStart + EEPROM_SIZE * i, 4, true); 31 | // TODO: is the following really ok? 32 | // it reads to all links, even if none is set 33 | if(sndAddrEEPROM == 0xFFFFFFFF) continue; 34 | if(sndAddrEEPROM != senderAddress) continue; 35 | // compare sender channel 36 | device->readEEPROM(&channelEEPROM, eepromStart + EEPROM_SIZE * i + 4, 1); 37 | if(channelEEPROM != senderChannel) continue; 38 | // compare target channel 39 | device->readEEPROM(&channelEEPROM, eepromStart + EEPROM_SIZE * i + 5, 1); 40 | if(channelEEPROM != targetChannel) continue; 41 | // ok, we have found a match 42 | // read actionType 43 | device->readEEPROM(&actionType, eepromStart + EEPROM_SIZE * i + 6, 1); 44 | // differs for short and long 45 | if (longPress) actionType >>= 2; 46 | actionType &= 0b00000011; 47 | uint8_t data; 48 | // we can have 49 | switch(actionType) { 50 | // 0 -> ON 51 | case 0: data = 200; 52 | break; 53 | // 1 -> OFF 54 | case 1: data = 0; 55 | break; 56 | // 2 -> INACTIVE 57 | case 2: continue; 58 | // 3 -> TOGGLE (default) 59 | case 3: data = 255; 60 | // break; 61 | }; 62 | device->set(targetChannel,1,&data); // channel, data length, data 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /libraries/src/HBWOneWireTempSensors.h: -------------------------------------------------------------------------------- 1 | /* 2 | * HBWOneWireTempSensors.h 3 | * 4 | * Created on: 02.04.2019 5 | * Author: loetmeister.de Vorlage: hglaser, thorsten@pferdekaemper.com, Hoschiq 6 | */ 7 | 8 | #ifndef HBWOneWireTempSensors_h 9 | #define HBWOneWireTempSensors_h 10 | 11 | /* Supported sensors */ 12 | //DS18S20 Gerätecode 0x10 13 | //DS18B20 Gerätecode 0x28 14 | //DS1822 Gerätecode 0x22 15 | 16 | 17 | #include "HBWired.h" 18 | #include 19 | 20 | #define DEBUG_OUTPUT // extra debug output on serial/USB 21 | //#define EXTRA_DEBUG_OUTPUT // even more debug output 22 | 23 | static const uint32_t OW_POLL_FREQUENCY = 1200; // read temperature every X milli seconds (not less than 900 ms! -> 750 ms conversion time @12 bit resolution) 24 | static const int16_t DEFAULT_TEMP = -27315; // for unused channels 25 | static const int16_t ERROR_TEMP = -27314; // CRC or read error 26 | #define OW_DEVICE_ADDRESS_SIZE 8 // fixed length for temp sensors address 27 | 28 | #define OW_DEVICE_ERROR_COUNT 3 // sensor in error state if counted down to 0. Decremented on every failed read or CRC error 29 | 30 | #define OW_CHAN_INIT 0xFF 31 | 32 | // config of each sensor, address step 14 33 | struct hbw_config_onewire_temp { 34 | uint8_t send_delta_temp; // Temperaturdifferenz, ab der gesendet wird 35 | uint8_t offset; // offset in c°C (-1.27..+1.27 °C) 36 | uint16_t send_min_interval; // Minimum-Sendeintervall 37 | uint16_t send_max_interval; // Maximum-Sendeintervall 38 | uint8_t address[OW_DEVICE_ADDRESS_SIZE]; // 1-Wire-Adresse 39 | // TODO: check if address can moved to seperate array, to only keep pointer here (ow_addr* ..?/ uint8_t* address = (uint8_t*)&ow_addr...; uint8_t ow_addr[8]) 40 | }; 41 | 42 | 43 | // Class HBWOneWireTempSensors 44 | class HBWOneWireTemp : public HBWChannel { 45 | public: 46 | HBWOneWireTemp(OneWire* _ow, hbw_config_onewire_temp* _config, uint32_t* _owLastReadTime, uint8_t* _owCurrentChannel); 47 | virtual void loop(HBWDevice*, uint8_t channel); 48 | virtual uint8_t get(uint8_t* data); 49 | virtual void afterReadConfig(); 50 | static void sensorSearch(OneWire* ow, hbw_config_onewire_temp** _config, uint8_t channels, uint8_t address_start); 51 | 52 | enum TempSensor_State { 53 | ACTION_START_CONVERSION = 0, 54 | ACTION_READ_TEMP 55 | }; 56 | 57 | 58 | private: 59 | int16_t oneWireReadTemp(); 60 | void oneWireStartConversion(); 61 | OneWire* ow {NULL}; 62 | hbw_config_onewire_temp* config; 63 | uint8_t* owCurrentChannel; // channel currently running conversion - can only be one at a time 64 | uint32_t* owLastReadTime; // when was the onewire sensor (actually the bus) last prompted 65 | int16_t currentTemp; // temperatures in m°C 66 | int16_t lastSentTemp; // temperature measured on last send 67 | uint32_t lastSentTime; // time of last send 68 | uint8_t errorCount; // channel/sensor in error state if counted down to 0. Decremented on every failed read 69 | uint8_t action; // current action: measure, read temp 70 | boolean errorWasSend; // flag to indicate if ERROR_TEMP was send 71 | boolean isAllZeros; // indicate that current device read was blank (usually happens when device gets disconnected) 72 | 73 | static bool deviceInvalidOrEmptyID(uint8_t deviceType); 74 | static const uint8_t DS18S20_ID = 0x10; 75 | static const uint8_t DS1822_ID = 0x22; 76 | static const uint8_t DS18B20_ID = 0x28; 77 | }; 78 | 79 | 80 | // macro to print OneWire address by hbwdebug (just used to keep the main code a bit more readable....) 81 | inline void m_hbwdebug_ow_address(uint8_t* address) { 82 | for (uint8_t i = 0; i < OW_DEVICE_ADDRESS_SIZE; i++) { 83 | hbwdebughex(address[i]); 84 | } 85 | }; 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /libraries/src/HBWPids.h: -------------------------------------------------------------------------------- 1 | /* 2 | * HBWPids.h 3 | * 4 | * Created on: 15.04.2019 5 | * loetmeister.de 6 | * 7 | * Author: Harald Glaser 8 | * some parts from the Arduino PID Library - Version 1.1.1 9 | * by Brett Beauregard brettbeauregard.com 10 | */ 11 | 12 | #ifndef HBWPIDS_H_ 13 | #define HBWPIDS_H_ 14 | 15 | 16 | #include "HBWOneWireTempSensors.h" 17 | #include "HBWired.h" 18 | #include "HBWValve.h" 19 | 20 | #define DEBUG_OUTPUT // debug output on serial/USB 21 | 22 | 23 | #define FIXED_SAMPLE_TIME 1000 // pid compute every second. Removes setSampleTime() from code 24 | 25 | 26 | // config of one PID channel, address step 9 27 | struct hbw_config_pid { 28 | uint8_t startMode:1; // 0x..:1 1=automatic 0=manual 29 | uint8_t :7; //fillup //0x..:1-8 30 | uint16_t kp; // proportional 31 | uint16_t ki; // integral 32 | uint16_t kd; // derivative 33 | uint8_t windowSize; // 10 seconds steps = max 2540 seconds (windowSize == CYCLE_TIME in XML) 34 | uint8_t setPoint; // default setPoint (range 0.1 - 25.4°C) 35 | }; 36 | 37 | 38 | // Class HBWPids 39 | class HBWPids : public HBWChannel { 40 | public: 41 | HBWPids(HBWValve* _valve, hbw_config_pid* _config); 42 | virtual void loop(HBWDevice*, uint8_t channel); 43 | virtual uint8_t get(uint8_t* data); 44 | virtual void set(HBWDevice*, uint8_t length, uint8_t const * const data); 45 | virtual void setInfo(HBWDevice*, uint8_t length, uint8_t const * const data); 46 | virtual void afterReadConfig(); 47 | 48 | private: 49 | hbw_config_pid* config; 50 | HBWValve* valve {NULL}; // linked valve channel, needs input value of 0-200 (maps to 0-100%) 51 | 52 | bool initDone; 53 | bool autoTuneRunning; // TODO: implement // 0 = off ; 1 = autotune running 54 | bool inErrorState; 55 | bool inAuto; // 1 = automatic ; 0 = manual 56 | bool oldInAuto; // auto or manual state stored here, when in error pos. 57 | int16_t setPoint; // temperatures in m°C 58 | uint32_t windowStartTime; 59 | 60 | // pidlib 61 | int16_t input, lastInput; 62 | #ifdef FIXED_SAMPLE_TIME 63 | static const uint16_t sampleTime = FIXED_SAMPLE_TIME; 64 | #else 65 | uint32_t sampleTime = 100; // lib default, 100 ms 66 | #endif 67 | uint32_t lastPidTime; // pid computes every sampleTime 68 | double output, outputSum, outMax; 69 | double kp, ki, kd; 70 | 71 | void autoTune(); 72 | int32_t mymap(double x, double in_max, double out_max); 73 | //pid lib 74 | void compute(); 75 | void setTunings(double Kp, double Ki, double Kd); 76 | void setSampleTime(int NewSampleTime); 77 | void setOutputLimits(double Max); 78 | void setMode(bool Mode); 79 | void initialize(); 80 | 81 | static const bool MANUAL = false; 82 | static const bool AUTOMATIC = true; 83 | static const bool SET_BY_PID = true; 84 | static const int16_t DEFAULT_SETPOINT = 2100; // 21.00 °C 85 | 86 | }; 87 | 88 | 89 | #endif /* HBWPIDS_H_ */ 90 | -------------------------------------------------------------------------------- /libraries/src/HBWSenEP.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * HBWSenEP.cpp 3 | * 4 | * Created on: 30.04.2019 5 | * Author: loetmeister.de 6 | * Vorlage: Markus, Thorsten 7 | */ 8 | 9 | 10 | #include "HBWSenEP.h" 11 | 12 | 13 | // constructor 14 | HBWSenEP::HBWSenEP(uint8_t _pin, hbw_config_sen_ep* _config, boolean _activeHigh) { 15 | pin = _pin; 16 | config = _config; 17 | activeHigh = _activeHigh; 18 | 19 | currentCount = 0; 20 | lastSentCount = 0; 21 | lastSentTime = 0; 22 | lastPortReadTime = 0; 23 | 24 | if (activeHigh) pinMode(pin, INPUT); 25 | else pinMode(pin, INPUT_PULLUP); // pullup only for activeLow 26 | } 27 | 28 | // constructor when using INTERRUPT based counter 29 | HBWSenEP::HBWSenEP(volatile uint16_t* _counter, hbw_config_sen_ep* _config, boolean _activeHigh) { 30 | counter = _counter; 31 | config = _config; 32 | activeHigh = _activeHigh; 33 | 34 | pin = NOT_A_PIN; 35 | currentCount = 0; 36 | lastSentCount = 0; 37 | lastSentTime = 0; 38 | lastPortReadTime = 0; 39 | } 40 | 41 | 42 | // channel specific settings or defaults 43 | // (This function is called after device read config from EEPROM) 44 | void HBWSenEP::afterReadConfig() { 45 | if(config->send_delta_count == 0xFFFF) config->send_delta_count = 1; 46 | if(config->send_min_interval == 0xFFFF) config->send_min_interval = 10; 47 | if(config->send_max_interval == 0xFFFF) config->send_max_interval = 600; // 10 minutes 48 | 49 | #ifdef DEBUG_OUTPUT 50 | hbwdebug(F("Pin: ")); hbwdebug(pin); hbwdebug(F(" enabled: ")); hbwdebug(config->enabled);hbwdebug(F("\n")); 51 | // hbwdebug(F(" poll_time: ")); hbwdebug((uint8_t)config->polling_time *10); hbwdebug(F("ms\n")); 52 | #endif 53 | } 54 | 55 | 56 | /* standard public function - returns length of data array. Data array contains current channel reading */ 57 | uint8_t HBWSenEP::get(uint8_t* data) { 58 | 59 | // MSB first 60 | *data++ = (currentCount >> 8); 61 | *data = currentCount & 0xFF; 62 | return 2; 63 | } 64 | 65 | 66 | void HBWSenEP::loop(HBWDevice* device, uint8_t channel) { 67 | 68 | if (!config->enabled) { // skip disabled channels, reset counter 69 | currentCount = 0; 70 | lastSentCount = 0; 71 | return; 72 | } 73 | 74 | uint32_t now = millis(); 75 | 76 | //skip this if ISR is used 77 | if (pin != NOT_A_PIN) { 78 | currentPortState = readInput(pin); 79 | 80 | if (currentPortState == LOW) 81 | { 82 | if (!lastPortReadTime) // not pressed yet 83 | { 84 | lastPortReadTime = (now == 0) ? 1 : now; 85 | portStateChange = true; 86 | } 87 | else if (now - lastPortReadTime > DEBOUNCE_DELAY && portStateChange) { 88 | // only count transition from high to low - once 89 | portStateChange = false; 90 | currentCount++; 91 | #ifdef DEBUG_OUTPUT 92 | hbwdebug(F("Pin: ")); hbwdebug(pin); hbwdebug(F(" COUNT:")); hbwdebug(currentCount);hbwdebug(F("\n")); 93 | #endif 94 | } 95 | } 96 | else { 97 | portStateChange = true; 98 | lastPortReadTime = 0; 99 | } 100 | } 101 | else 102 | { 103 | currentCount = *counter; // read current counter value - updated by interrupt function in the background 104 | } 105 | 106 | // check if some data needed to be send 107 | // do not send before min interval 108 | if (config->send_min_interval && now - lastSentTime < (uint32_t)config->send_min_interval * 1000) return; 109 | if ((config->send_max_interval && now - lastSentTime >= (uint32_t)config->send_max_interval * 1000) || 110 | (config->send_delta_count && (currentCount - lastSentCount ) >= config->send_delta_count)) { 111 | // send 112 | uint8_t level[2]; 113 | get(level); 114 | // if bus is busy, then we try again in the next round 115 | if (device->sendInfoMessage(channel, 2, level) != HBWDevice::BUS_BUSY) { // level has always 2 byte here 116 | lastSentCount = currentCount; 117 | lastSentTime = now; 118 | 119 | #ifdef DEBUG_OUTPUT 120 | hbwdebug(F("Ch: ")); hbwdebug(channel); hbwdebug(F(" send: ")); hbwdebug(lastSentCount); hbwdebug(F("\n")); 121 | #endif 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /libraries/src/HBWSenEP.h: -------------------------------------------------------------------------------- 1 | /* 2 | * HBWSenEP.h 3 | * 4 | * Created on: 30.04.2019 5 | * Author: loetmeister.de 6 | * Vorlage: Markus, Thorsten 7 | */ 8 | 9 | #ifndef HBWSenEP_h 10 | #define HBWSenEP_h 11 | 12 | 13 | #include "HBWired.h" 14 | 15 | // #define DEBUG_OUTPUT // extra debug output on serial/USB 16 | 17 | // S0-Puls muss laut Definition mindestens 30ms lang sein - Abtastungsrate ist nicht garantiert. 18 | // Besser INTERRUPT nutzen -> HBW-Sen-EP_interrupt.h 19 | 20 | #define DEBOUNCE_DELAY 10 // 10 ms. S0 input debounce (INTERRUPT based debounce set in HBW-Sen-EP_interrupt.h) 21 | 22 | 23 | // config of each sensor, address step 9 24 | struct hbw_config_sen_ep { 25 | uint8_t enabled :1; // 1=enabled, 0=disabled 26 | uint8_t n_inverted :1; // 0=inverted, 1=not inverted (device reset will set to 1!) 27 | uint8_t dummy :6; 28 | uint16_t send_delta_count; // Zählerdifferenz, ab der gesendet wird 29 | uint16_t send_min_interval; // Minimum-Sendeintervall 30 | uint16_t send_max_interval; // Maximum-Sendeintervall 31 | //uint8_t counts_per_unit; // TODO: implement? What functionality needs it? 32 | uint16_t unused; 33 | }; 34 | 35 | 36 | // Class HBWSenEP 37 | class HBWSenEP : public HBWChannel { 38 | public: 39 | HBWSenEP(uint8_t _pin, hbw_config_sen_ep* _config, boolean _activeHigh = false); 40 | HBWSenEP(volatile uint16_t* _counter, hbw_config_sen_ep* _config, boolean _activeHigh = false); 41 | virtual void loop(HBWDevice*, uint8_t channel); 42 | virtual uint8_t get(uint8_t* data); 43 | virtual void afterReadConfig(); 44 | 45 | private: 46 | hbw_config_sen_ep* config; 47 | uint8_t pin; 48 | volatile uint16_t* counter; 49 | 50 | boolean activeHigh; // activeHigh=true -> input active high, else active low 51 | boolean currentPortState; 52 | boolean portStateChange; 53 | uint16_t currentCount; 54 | uint16_t lastSentCount; // counter on last send 55 | uint32_t lastSentTime; // time of last send 56 | uint32_t lastPortReadTime; // time of last port read 57 | 58 | inline boolean readInput(uint8_t Pin) { 59 | boolean reading = (digitalRead(Pin) ^ !config->n_inverted); 60 | return (activeHigh ^ reading); 61 | } 62 | }; 63 | 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /libraries/src/HBWSenSC.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * HBWSenSC.cpp 3 | * 4 | * sensor/shutter contact 5 | * Query to this type of channel will return "contact_closed" or "contact_open" (boolean) 6 | * No peering. I-Message/notify on status change can be enabled by NOTIFY: on/off 7 | * 8 | * Updated: 09.08.2020 9 | * www.loetmeister.de 10 | * 11 | */ 12 | 13 | #include "HBWSenSC.h" 14 | 15 | // Class HBWSenSC 16 | HBWSenSC::HBWSenSC(uint8_t _pin, hbw_config_senSC* _config, boolean _activeHigh) { 17 | pin = _pin; 18 | config = _config; 19 | activeHigh = _activeHigh; 20 | keyPressedMillis = 0; 21 | clearFeedback(); 22 | initDone = false; 23 | if (activeHigh) pinMode(pin, INPUT); 24 | else pinMode(pin, INPUT_PULLUP); // pullup only for activeLow 25 | }; 26 | 27 | 28 | /* standard public function - returns length of data array. Data array contains current channel reading */ 29 | uint8_t HBWSenSC::get(uint8_t* data) { 30 | 31 | (*data) = currentValue ? 200 : 0; 32 | 33 | return 1; 34 | }; 35 | 36 | 37 | /* standard public function - called by main loop for every channel in sequential order */ 38 | void HBWSenSC::loop(HBWDevice* device, uint8_t channel) { 39 | 40 | //avoid notify messages on device start 41 | if (initDone == false) { 42 | currentValue = readScInput(); 43 | initDone = true; 44 | return; 45 | } 46 | 47 | if (!config->n_input_locked) return; // channel locked? 48 | 49 | uint32_t now = millis(); 50 | 51 | boolean buttonState = readScInput(); 52 | 53 | if (buttonState != currentValue) { 54 | 55 | if (!keyPressedMillis) { 56 | // Taste war vorher nicht gedrueckt 57 | keyPressedMillis = now ? now : 1; 58 | } 59 | else if (now - keyPressedMillis >= DEBOUNCE_TIME) { 60 | currentValue = buttonState; 61 | keyPressedMillis = 0; 62 | 63 | clearFeedback(); // rapid state changes would reset the timer and not flood the bus with messages 64 | setFeedback(device, !config->notify_disabled, DEBOUNCE_TIME *10); 65 | 66 | #ifdef DEBUG_OUTPUT 67 | hbwdebug(F("sc-ch:")); 68 | hbwdebug(channel); 69 | hbwdebug(F(" val:")); 70 | hbwdebug(currentValue); 71 | hbwdebug(F("\n")); 72 | #endif 73 | } 74 | } 75 | else { 76 | keyPressedMillis = 0; 77 | } 78 | 79 | // feedback trigger set? 80 | checkFeedback(device, channel); 81 | }; 82 | 83 | -------------------------------------------------------------------------------- /libraries/src/HBWSenSC.h: -------------------------------------------------------------------------------- 1 | /* 2 | * HBWSenSC.h 3 | * 4 | * sensor/shutter contact 5 | * Query to this type of channel will return "contact_closed" or "contact_open" (boolean) 6 | * No peering. I-Message/notify on status change can be enabled by NOTIFY: on/off 7 | * 8 | * www.loetmeister.de 9 | * 10 | */ 11 | 12 | #ifndef HBWSenSC_h 13 | #define HBWSenSC_h 14 | 15 | #include 16 | #include "HBWired.h" 17 | 18 | 19 | //#define DEBUG_OUTPUT // extra debug output on serial/USB 20 | 21 | 22 | // config of each sensor channel, address step 1 23 | struct hbw_config_senSC { 24 | uint8_t n_input_locked:1; // +0.0 0=LOCKED, 1=UNLOCKED (default) 25 | uint8_t n_inverted:1; // +0.1 0=inverted, 1=not inverted (default) 26 | uint8_t notify_disabled:1; // +0.2 0=ENABLED, 1=DISABLED (default) 27 | uint8_t :5; // +0.3-7 28 | //uint8_t :3; // make DEBOUNCE_TIME configurable? (200ms steps, start at 0 = 200.. 7 = 1400) 29 | }; 30 | 31 | 32 | // Class HBWSenSC 33 | class HBWSenSC : public HBWChannel { 34 | public: 35 | HBWSenSC(uint8_t _pin, hbw_config_senSC* _config, boolean _activeHigh = false); 36 | virtual void loop(HBWDevice*, uint8_t channel); 37 | virtual uint8_t get(uint8_t* data); 38 | 39 | private: 40 | uint8_t pin; // Pin 41 | hbw_config_senSC* config; 42 | uint32_t keyPressedMillis; // Zeit, zu der die Taste gedrueckt wurde (fuer's Entprellen) 43 | boolean currentValue; 44 | boolean initDone; 45 | boolean activeHigh; // activeHigh=true -> input active high, else active low 46 | 47 | inline boolean readScInput() { 48 | boolean reading = (digitalRead(pin) ^ !config->n_inverted); 49 | return (activeHigh ^ reading); 50 | } 51 | 52 | static const uint8_t DEBOUNCE_TIME = 88; // ms 53 | }; 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /libraries/src/HBWSoftwareSerial.h: -------------------------------------------------------------------------------- 1 | /* 2 | HBWSoftwareSerial, added even parity bit to default SoftwareSerial.h 3 | SoftwareSerial.h (formerly NewSoftSerial.h) - 4 | Multi-instance software serial library for Arduino/Wiring 5 | -- Interrupt-driven receive and other improvements by ladyada 6 | (http://ladyada.net) 7 | -- Tuning, circular buffer, derivation from class Print/Stream, 8 | multi-instance support, porting to 8MHz processors, 9 | various optimizations, PROGMEM delay tables, inverse logic and 10 | direct port writing by Mikal Hart (http://www.arduiniana.org) 11 | -- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com) 12 | -- 20MHz processor support by Garrett Mace (http://www.macetech.com) 13 | -- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/) 14 | 15 | This library is free software; you can redistribute it and/or 16 | modify it under the terms of the GNU Lesser General Public 17 | License as published by the Free Software Foundation; either 18 | version 2.1 of the License, or (at your option) any later version. 19 | 20 | This library is distributed in the hope that it will be useful, 21 | but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 23 | Lesser General Public License for more details. 24 | 25 | You should have received a copy of the GNU Lesser General Public 26 | License along with this library; if not, write to the Free Software 27 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 28 | 29 | The latest version of this library can always be found at 30 | http://arduiniana.org. 31 | */ 32 | 33 | #ifndef SoftwareSerial_h 34 | #define SoftwareSerial_h 35 | 36 | #include 37 | #include 38 | 39 | /****************************************************************************** 40 | * Definitions 41 | ******************************************************************************/ 42 | 43 | #ifndef _SS_MAX_RX_BUFF 44 | #define _SS_MAX_RX_BUFF 64 // RX buffer size 45 | #endif 46 | 47 | #ifndef GCC_VERSION 48 | #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) 49 | #endif 50 | 51 | class HBWSoftwareSerial : public Stream 52 | { 53 | private: 54 | // per object data 55 | uint8_t _receivePin; 56 | uint8_t _receiveBitMask; 57 | volatile uint8_t *_receivePortRegister; 58 | uint8_t _transmitBitMask; 59 | volatile uint8_t *_transmitPortRegister; 60 | volatile uint8_t *_pcint_maskreg; 61 | uint8_t _pcint_maskvalue; 62 | 63 | // Expressed as 4-cycle delays (must never be 0!) 64 | uint16_t _rx_delay_centering; 65 | uint16_t _rx_delay_intrabit; 66 | uint16_t _rx_delay_stopbit; 67 | uint16_t _tx_delay; 68 | 69 | uint16_t _buffer_overflow:1; 70 | // uint16_t _inverse_logic:1; 71 | static const uint16_t _inverse_logic = false; // inverse_logic option not needed 72 | 73 | // static data 74 | static uint8_t _receive_buffer[_SS_MAX_RX_BUFF]; 75 | static volatile uint8_t _receive_buffer_tail; 76 | static volatile uint8_t _receive_buffer_head; 77 | static HBWSoftwareSerial *active_object; 78 | 79 | // private methods 80 | inline void recv() __attribute__((__always_inline__)); 81 | uint8_t rx_pin_read(); 82 | void setTX(uint8_t transmitPin); 83 | void setRX(uint8_t receivePin); 84 | inline void setRxIntMsk(bool enable) __attribute__((__always_inline__)); 85 | 86 | // Return num - sub, or 1 if the result would be < 1 87 | static uint16_t subtract_cap(uint16_t num, uint16_t sub); 88 | 89 | // private static method for timing 90 | static inline void tunedDelay(uint16_t delay); 91 | 92 | public: 93 | // public methods 94 | HBWSoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic = false); 95 | ~HBWSoftwareSerial(); 96 | void begin(long speed = 19200); 97 | bool listen(); 98 | void end(); 99 | bool isListening() { return this == active_object; } 100 | bool stopListening(); 101 | bool overflow() { bool ret = _buffer_overflow; if (ret) _buffer_overflow = false; return ret; } 102 | int peek(); 103 | 104 | virtual size_t write(uint8_t byte); 105 | virtual int read(); 106 | virtual int available(); 107 | virtual void flush(); 108 | operator bool() { return true; } 109 | 110 | using Print::write; 111 | 112 | // public only for easy access by interrupt handlers 113 | static inline void handle_interrupt() __attribute__((__always_inline__)); 114 | }; 115 | 116 | #endif 117 | -------------------------------------------------------------------------------- /libraries/src/HBWSwitch.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "HBWSwitch.h" 3 | 4 | // Switches 5 | HBWSwitch::HBWSwitch(uint8_t _pin, hbw_config_switch* _config) { 6 | pin = _pin; 7 | config = _config; 8 | clearFeedback(); 9 | currentState = UNKNOWN_STATE; 10 | }; 11 | 12 | 13 | // channel specific settings or defaults 14 | // (This function is called after device read config from EEPROM) 15 | void HBWSwitch::afterReadConfig() { 16 | if (currentState == UNKNOWN_STATE) { 17 | // All off on init, but consider inverted setting 18 | digitalWrite(pin, config->n_inverted ? LOW : HIGH); // 0=inverted, 1=not inverted (device reset will set to 1!) 19 | pinMode(pin,OUTPUT); 20 | currentState = OFF_STATE; 21 | } 22 | else { 23 | // Do not reset outputs on config change (EEPROM re-reads), but update its state 24 | digitalWrite(pin, !currentState ^ config->n_inverted); 25 | } 26 | } 27 | 28 | 29 | void HBWSwitch::set(HBWDevice* device, uint8_t length, uint8_t const * const data) { 30 | if (config->output_unlocked) { //0=LOCKED, 1=UNLOCKED 31 | if(*data > 200) { // toggle 32 | digitalWrite(pin, digitalRead(pin) ? LOW : HIGH); 33 | currentState = (currentState ? OFF_STATE : ON_STATE); 34 | } 35 | else { // on or off 36 | if (*data) { 37 | digitalWrite(pin, LOW ^ config->n_inverted); // on (if not inverted) 38 | currentState = ON_STATE; 39 | } 40 | else { 41 | digitalWrite(pin, HIGH ^ config->n_inverted); // off (if not inverted) 42 | currentState = OFF_STATE; 43 | } 44 | } 45 | } 46 | // Logging 47 | // set trigger to send info/notify message in loop() 48 | setFeedback(device, config->logging); 49 | }; 50 | 51 | 52 | uint8_t HBWSwitch::get(uint8_t* data) { 53 | if (currentState) 54 | (*data) = 200; 55 | else 56 | (*data) = 0; 57 | return 1; 58 | }; 59 | 60 | 61 | void HBWSwitch::loop(HBWDevice* device, uint8_t channel) { 62 | // feedback trigger set? 63 | checkFeedback(device, channel); 64 | } 65 | 66 | -------------------------------------------------------------------------------- /libraries/src/HBWSwitch.h: -------------------------------------------------------------------------------- 1 | // Switches 2 | 3 | #ifndef HBWSwitch_h 4 | #define HBWSwitch_h 5 | 6 | #include 7 | #include "HBWired.h" 8 | 9 | #define OFF_STATE 0 10 | #define ON_STATE 1 11 | #define UNKNOWN_STATE 0xFE 12 | 13 | // TODO: wahrscheinlich ist es besser, bei EEPROM-re-read 14 | // callbacks fuer die einzelnen Kanaele aufzurufen 15 | // und den Kanaelen nur den Anfang "ihres" EEPROMs zu sagen 16 | // config of one channel, address step 2 17 | struct hbw_config_switch { 18 | uint8_t logging:1; // 0x0000 19 | uint8_t output_unlocked:1; // 0x07:1 0=LOCKED, 1=UNLOCKED 20 | uint8_t n_inverted:1; // 0x07:2 0=inverted, 1=not inverted (device reset will set to 1!) 21 | uint8_t :5; // 0x0000 22 | uint8_t dummy; 23 | }; 24 | 25 | 26 | class HBWSwitch : public HBWChannel { 27 | public: 28 | HBWSwitch(uint8_t _pin, hbw_config_switch* _config); 29 | virtual uint8_t get(uint8_t* data); 30 | virtual void loop(HBWDevice*, uint8_t channel); 31 | virtual void set(HBWDevice*, uint8_t length, uint8_t const * const data); 32 | virtual void afterReadConfig(); 33 | 34 | protected: 35 | uint8_t pin; 36 | uint8_t currentState; // keep track of logical state, not real IO 37 | 38 | private: 39 | hbw_config_switch* config; // logging 40 | }; 41 | 42 | #endif -------------------------------------------------------------------------------- /libraries/src/HBWValve.h: -------------------------------------------------------------------------------- 1 | /* 2 | * HBWValve.h 3 | * 4 | * Created on: 05.05.2019 5 | * loetmeister.de 6 | * 7 | * 8 | * 15.02.2015 9 | * Author: hglaser 10 | * Eine einfache Ventilsteuerung für mein Thermisches 24V Ventil. 11 | * Verwendet wird zur Umrechnung der Ventilstellung die von FHEM gesendet wird, 12 | * "time proportioning control" eine Art extrem langsames PWM. Bei über 50% schaltet 13 | * das Ventil zuerst ein, unter 50% zuerst aus. Nach einer Änderung wird die erste 14 | * Ein- oder Auszeit einmal halbiert 15 | * 16 | * 17 | *25 % ____|----|________|----|_______| 18 | * aus ein aus ein aus... 19 | *50 % ____|--------|________|--------|____ 20 | * aus ein aus ein aus... 21 | *75 % ----|____|--------|____|-------- 22 | * ein aus ein aus ein... 23 | * 24 | */ 25 | 26 | #ifndef HBWVAVLE_H_ 27 | #define HBWVAVLE_H_ 28 | 29 | 30 | #include "HBWired.h" 31 | 32 | #define DEBUG_OUTPUT // debug output on serial/USB 33 | 34 | 35 | #define OFF LOW 36 | #define ON HIGH 37 | #define VENTON true 38 | #define VENTOFF false 39 | 40 | 41 | // need to match frame definition in XML: 42 | #define SET_TOGGLE_AUTOMATIC 201 43 | #define SET_MANUAL 203 44 | #define SET_AUTOMATIC 205 45 | 46 | 47 | // config of one valve channel, address step 4 48 | struct hbw_config_valve { 49 | uint8_t logging:1; // +0.0 1=on 0=off 50 | uint8_t unlocked:1; // +0.1 0=LOCKED, 1=UNLOCKED; locked channels will retain level/error_pos. Set error_pos to 0 to disable a channel completely. A locked channel can still be controlled by its PID channel. If PIDs are used, set them to manual start up. 51 | uint8_t n_inverted:1; // +0.2 inverted logic (use NO valves, NC is default) 52 | uint8_t :5; //fillup //0x..:3-8 53 | uint8_t error_pos; // default/error position 54 | uint8_t valveSwitchTime; // (factor 10! max 2540 seconds) Time the valve needs to reach 100% (NC:open or NO:closed state) 55 | uint8_t limit_upper:2; // 100%, 90%, 80%, 70% ... do not drive valve higher than selected value (e.g. if valve already remains open at 90%) 56 | uint8_t limit_lower:2; // 0%, 5%, 10%, 15% ... do not actuate valve below selected value (e.g. if valve does not open below 10% at all) 57 | uint8_t dummy :4; 58 | // TODO: option for anti stick? valve_protect (e.g. open valves once a week?) 59 | }; 60 | 61 | 62 | // Class HBWVavle 63 | class HBWValve : public HBWChannel { 64 | public: 65 | HBWValve(uint8_t _pin, hbw_config_valve* _config); 66 | virtual void loop(HBWDevice*, uint8_t channel); 67 | virtual uint8_t get(uint8_t* data); 68 | virtual void set(HBWDevice*, uint8_t length, uint8_t const * const data, bool setByPID); 69 | virtual void set(HBWDevice*, uint8_t length, uint8_t const * const data); 70 | virtual void afterReadConfig(); 71 | 72 | // linked PID channel access 73 | bool getPidsInAuto(); 74 | void setPidsInAuto(bool newAuto); 75 | 76 | private: 77 | hbw_config_valve* config; 78 | uint8_t pin; 79 | 80 | uint8_t valveLevel; 81 | void setNewLevel(HBWDevice* device, uint8_t NewLevel); 82 | 83 | // output control 84 | inline void switchstate(bool State); 85 | uint16_t set_timer(bool firstState, bool status); 86 | uint16_t set_peakmiddle(uint16_t ontimer, uint16_t offtimer); 87 | bool first_on_or_off(uint16_t ontimer, uint16_t offtimer); 88 | bool init_new_state(); 89 | uint16_t set_ontimer(uint8_t VentPositionRequested); 90 | uint16_t set_offtimer(uint16_t ontimer); 91 | 92 | uint32_t outputChangeLastTime; // last time output state was changed 93 | uint16_t outputChangeNextDelay; // time until next state change 94 | uint16_t onTimer, offTimer; // current calculated on and of duration 95 | 96 | bool initDone; 97 | bool isFirstState; 98 | bool nextState; 99 | 100 | union tag_state_flags { // state_flags should not exeed one byte! 101 | struct state_flags { 102 | uint8_t notUsed :4; // lowest 4 bit are not used, based on XML state_flag definition 103 | uint8_t upDown :1; // Pid regelt hoch oder runter 104 | uint8_t inAuto :1; // 1 = automatic ; 0 = manual 105 | uint8_t status :1; // outputs on or off? 106 | //uint8_t fillup :1; // not used 107 | } element; 108 | uint8_t byte:8; 109 | } stateFlags; 110 | 111 | static const uint16_t OUTPUT_STARTUP_DELAY = 63; // 63 == 6.3 seconds 112 | }; 113 | 114 | #endif /* HBWVAVLE_H_ */ 115 | -------------------------------------------------------------------------------- /libraries/src/HBW_eeprom.h: -------------------------------------------------------------------------------- 1 | /* 2 | * HBW_eeprom.h 3 | * 4 | * Helper to allow for different EEPROM libs / different boards 5 | * 6 | * The EEPROM class must have write() and read() methods for single bytes. 7 | * When it does only write after read, you may want to use update() instead. 8 | * For I2C EEPROMs, it should also have an available() method. 9 | * 10 | * Created on: 10.07.2024 11 | * Author: loetmeister.de 12 | */ 13 | 14 | #ifndef _HBW_eeprom_h 15 | #define _HBW_eeprom_h 16 | 17 | 18 | #if defined (ARDUINO_ARCH_RP2040) 19 | #include 20 | class EEPROM24; // forward declare class 21 | extern EEPROM24* EepromPtr; 22 | // define this, if the class has no update() function, or you don't want to use it 23 | // #define EEPROM_no_update_function 24 | 25 | // max EEPROM address for HBW device. Usual EEPROM size is 1024 (as defined in device XML) 26 | #define E2END 0x3FF 27 | #else 28 | // define this, if the class has no update() function, or you don't want to use it 29 | #define EEPROM_no_update_function 30 | #include 31 | extern EEPROMClass* EepromPtr; 32 | #endif 33 | 34 | 35 | #endif /* _HBW_eeprom_h */ 36 | -------------------------------------------------------------------------------- /libraries/src/HBW_hardware.h: -------------------------------------------------------------------------------- 1 | /* 2 | * hardware.h 3 | * Macros for different function calls or defines, if not set by the board 4 | * 5 | * Created on: 23.05.2018 6 | * Author: loetmeister.de 7 | */ 8 | 9 | #ifndef _HBW_hardware_h 10 | #define _HBW_hardware_h 11 | 12 | 13 | //#define _HAS_BOOTLOADER_ // enable bootlader support of the device. BOOTSTART must be defined as well 14 | 15 | 16 | 17 | #ifndef NOT_A_PIN 18 | #define NOT_A_PIN 0xFF 19 | #endif 20 | 21 | 22 | /* Start Boot Program section and RAM address start */ 23 | #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) || defined (__AVR_ATmega328PB__) 24 | // Boot Size 2048 words 25 | #define BOOTSTART (0x3800) 26 | #elif defined (__AVR_ATmega32__) 27 | #define BOOTSTART (0x3800) 28 | #endif 29 | 30 | 31 | #if defined(__AVR_ATmega168__) 32 | #define RAMSTART (0x100) 33 | #define NRWWSTART (0x3800) 34 | #elif defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) 35 | #define RAMSTART (0x100) 36 | #define NRWWSTART (0x7000) 37 | #elif defined (__AVR_ATmega644P__) 38 | #define RAMSTART (0x100) 39 | #define NRWWSTART (0xE000) 40 | #elif defined(__AVR_ATtiny84__) 41 | #define RAMSTART (0x100) 42 | #define NRWWSTART (0x0000) 43 | #elif defined(__AVR_ATmega1280__) 44 | #define RAMSTART (0x200) 45 | #define NRWWSTART (0xE000) 46 | #elif defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__) 47 | #define RAMSTART (0x100) 48 | #define NRWWSTART (0x1800) 49 | #endif 50 | 51 | 52 | /* sleep macro. Timer for millis() must keep running! Don't sleep too deep... */ 53 | #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) || defined (__AVR_ATmega328PB__) 54 | // "idle" sleep mode (mode 0) 55 | #include 56 | #define POWERSAVE() set_sleep_mode(0); \ 57 | sleep_mode(); 58 | #elif defined (ARDUINO_ARCH_RP2040) 59 | // #define POWERSAVE() sleep modes seem to be unstable / complicated. Lower sys_clock instead... 60 | 61 | //#elif defined (__AVR_ATmega644P__)... // TODO: add others 62 | #endif 63 | 64 | 65 | /* watchdog macros, config, reboot and reset*/ 66 | #if defined (__AVR__) 67 | #include "avr/wdt.h" 68 | // if watchdog is used & active, just run into infinite loop to force reset 69 | #define RESET_HARDWARE() while(1){} 70 | #define ENABLE_WATCHDOG() wdt_enable(WDTO_1S) 71 | #define DISABLE_WATCHDOG() wdt_disable() 72 | #define RESET_WATCHDOG() wdt_reset() 73 | // Arduino Reset via Software function declaration, point to address 0 (reset vector) 74 | #define RESET_SOFTWARE() resetSoftware() 75 | #define WATCHDOG_CAUSED_RESET() MCUSR & (1 << WDRF) 76 | 77 | #elif defined (ARDUINO_ARCH_RP2040) 78 | #include 79 | #define ENABLE_WATCHDOG() watchdog_enable(1000, 0) 80 | #define DISABLE_WATCHDOG() watchdog_disable() 81 | #define RESET_WATCHDOG() watchdog_update() 82 | //watchdog_reboot(0, 0, 10); // watchdog fire after 10us and busy waits (SRAM_END will not be ignored,, when first parameter is 0) 83 | #define RESET_HARDWARE() watchdog_reboot(0, SRAM_END, 10);\ 84 | for (;;) { } 85 | // always reboot via watchdog 86 | #define RESET_SOFTWARE() RESET_HARDWARE() 87 | #define WATCHDOG_CAUSED_RESET() watchdog_caused_reboot() 88 | #endif 89 | 90 | #endif /* _HBW_hardware_h */ 91 | -------------------------------------------------------------------------------- /libraries/src/HBWired.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThorstenPferdekaemper/HBWired/27cbac299529a660c791c42f2cece74439513561/libraries/src/HBWired.cpp -------------------------------------------------------------------------------- /libraries/src/HBWlibStateMachine.h: -------------------------------------------------------------------------------- 1 | /* 2 | * HBWlibStateMachine 3 | * 4 | * Support lib for state machine 5 | * 6 | * http://loetmeister.de/Elektronik/homematic/ 7 | * 8 | */ 9 | 10 | #ifndef HBWlibStateMachine_h 11 | #define HBWlibStateMachine_h 12 | 13 | #include 14 | #include 15 | 16 | 17 | 18 | #define DELAY_NO 0x00 19 | #define DELAY_INFINITE 0xffffffff 20 | 21 | // #define ON_LEVEL_PRIO_HIGH 0 22 | // #define ON_LEVEL_PRIO_LOW 1 23 | 24 | #define BITMASK_ActionType 0b00001111 25 | #define BITMASK_LongMultiexecute 0b00100000 26 | #define BITMASK_OffTimeMode 0b01000000 27 | #define BITMASK_OnTimeMode 0b10000000 28 | 29 | #define BITMASK_OnDelayMode 0b00000001 30 | #define BITMASK_OnLevelPrio 0b00000010 31 | #define BITMASK_OffDelayBlink 0b00000100 32 | #define BITMASK_RampStartStep 0b11110000 33 | 34 | 35 | 36 | /* convert time value stored in EEPROM to milliseconds - 1 byte value */ 37 | inline uint32_t convertTime(uint8_t timeValue) { 38 | 39 | uint8_t factor = timeValue & 0xC0; // mask out factor (higest two bits) 40 | timeValue &= 0x3F; // keep time value only 41 | 42 | // factors: 1,60,1000,6000 (last one is not used) 43 | switch (factor) { 44 | case 0: // x1 45 | return (uint32_t)timeValue *1000; 46 | break; 47 | case 64: // x60 48 | return (uint32_t)timeValue *60000; 49 | break; 50 | case 128: // x1000 51 | return (uint32_t)timeValue *1000000; 52 | break; 53 | // case 192: // not used value 54 | // return 0; // TODO: check how to handle this properly, what does on/off time == 0 mean? infinite on/off?? 55 | //TODO: check; case 255: // not used value return DELAY_INFINITE? 56 | } 57 | return DELAY_INFINITE; //0 58 | }; 59 | 60 | 61 | /* convert time value stored in EEPROM to milliseconds - 2 byte value */ 62 | inline uint32_t convertTime(uint16_t timeValue) { 63 | 64 | uint8_t factor = timeValue >> 14; // mask out factor (higest two bits) 65 | timeValue &= 0x3FFF; // keep time value only 66 | 67 | // factors: 0.1,1,60,1000 (last one is not used) 68 | switch (factor) { 69 | case 0: // x0.1 70 | return (uint32_t)timeValue *100; 71 | break; 72 | case 1: // x1 73 | return (uint32_t)timeValue *1000; 74 | break; 75 | case 2: // x60 76 | return (uint32_t)timeValue *60000; 77 | break; 78 | // case 192: // not used value 79 | // return 0; // TODO: check how to handle this properly, what does on/off time == 0 mean? infinite on/off?? 80 | //TODO: check; case 255: // not used value return DELAY_INFINITE? 81 | } 82 | return DELAY_INFINITE; //0 83 | }; 84 | 85 | 86 | #endif 87 | --------------------------------------------------------------------------------