merged with release mega-20200305
merged with release mega-20200305
@@ -0,0 +1,36 @@
|
||||
.. include:: ../Plugin/_plugin_substitutions_p09x.repl
|
||||
.. _P092_page:
|
||||
|
||||
|P092_typename|
|
||||
==================================================
|
||||
|
||||
|P092_shortinfo|
|
||||
|
||||
Plugin details
|
||||
--------------
|
||||
|
||||
Type: |P092_type|
|
||||
|
||||
Name: |P092_name|
|
||||
|
||||
Status: |P092_status|
|
||||
|
||||
GitHub: |P092_github|_
|
||||
|
||||
Maintainer: |P092_maintainer|
|
||||
|
||||
Used libraries: |P092_usedlibraries|
|
||||
|
||||
Supported hardware
|
||||
------------------
|
||||
|
||||
|P092_usedby|
|
||||
|
||||
Change log
|
||||
----------
|
||||
|
||||
.. versionadded:: 1.0
|
||||
...
|
||||
|
||||
|added|
|
||||
Initial release version.
|
||||
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 84 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 19 KiB |
@@ -0,0 +1,50 @@
|
||||
.. include:: ../Plugin/_plugin_substitutions_p09x.repl
|
||||
.. _P092_DLbus_page:
|
||||
|
||||
DL bus
|
||||
======
|
||||
|
||||
|P092_typename|
|
||||
|P092_status|
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
The DL-Bus is used in control units e.g. sold by `Technische Alternative <http://www.ta.co.at/>`_.
|
||||
The DL-Bus serves as a bus line for various external sensors and modules.
|
||||
The DL-Bus is a bidirectional data line and only compatible with products of Technische Alternative.
|
||||
|
||||
The data transmission looks as follows:
|
||||
* In an infinite loop, a logging data frame is created by the control one after the others on the data line.
|
||||
|
||||
Up to 4 sensor measured value queries (master/slave) can be made between the individual logging data frames on the DL bus.
|
||||
* So that the beginning of a data frame can be detected, a SYNC of 16 high bits is sent before the first data byte.
|
||||
* The data transmission is carried out as Manchester code (EXOR linked) with a display clock of 50 or 488Hz (depending on control type).
|
||||
|
||||
This is necessary to ensure the supply voltage of the logger and DL sensors from the data signal.
|
||||
If the receiver is synchronized to the display clock, the correct bit value appears always during the second half period of the data bit (inverted in the first half period).
|
||||
|
||||
Wiring
|
||||
------
|
||||
|
||||
The DL-Bus consists of 2 wires: DL and GND (sensor ground).
|
||||
The power supply for the DL-Bus sensors is supplied via the DL-Bus itself.
|
||||
Some DL-Bus devices can/must be powered via a 12V source, e.g. that of the CAN bus (this is explicitly noted in the operating manual of that sensor).
|
||||
The cable routing can be star-shaped or serial (from one device to the next).
|
||||
Any cable with a cross-section of 0.75 mm2 up to a maximum length of 30 m can be used as a data cable.
|
||||
Over 30 m, the use of shielded cables is recommended, which increases the permissible length of the cable to 100 m.
|
||||
|
||||
Protocol
|
||||
--------
|
||||
|
||||
Transmission of a data byte
|
||||
.. image:: P092_DL_bus_databyte.png
|
||||
|
||||
Transmission of a data frame
|
||||
.. image:: P092_DL_bus_dataframe.png
|
||||
|
||||
Data frame on the DL bus
|
||||
.. image:: P092_DL_bus_dataframelog.png
|
||||
|
||||
Display clock
|
||||
.. image:: P092_DL_bus_displayclock.png
|
||||
|
After Width: | Height: | Size: 61 KiB |
@@ -0,0 +1,76 @@
|
||||
.. include:: ../Plugin/_plugin_substitutions_p09x.repl
|
||||
.. _P092_ESR21_page:
|
||||
|
||||
ESR21
|
||||
=====
|
||||
|
||||
|P092_typename|
|
||||
|P092_status|
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
The ESR21 unit is a simple solar control.
|
||||
The ESR21 unit is a differential control that can be used in many ways
|
||||
|
||||
The DL bus runs at 12 volts.
|
||||
The data frame consist of 30 bytes (excluding sync and CRC).
|
||||
The data are transmitted @ 488Hz, therefore the transmission of one data set takes about 0.67 seconds.
|
||||
.. image:: P092_ESR21.png
|
||||
|
||||
Wiring
|
||||
------
|
||||
|
||||
.. image:: P092_12V_Wiring.png
|
||||
|
||||
Protocol
|
||||
--------
|
||||
|
||||
.. image:: P092_ESR21_Protocol.png
|
||||
|
||||
Setup
|
||||
-----
|
||||
|
||||
.. note:: A new device task must be created for each value to be read from the DL bus!
|
||||
|
||||
.. image:: P092_Setup.png
|
||||
|
||||
Task settings
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
* **Device**: Heating - DL-Bus (Technische Alternative)
|
||||
* **Name**: Name of the task (example name **ValueN**, where N is a number).
|
||||
* **Enable**: Should the task be enabled or not
|
||||
|
||||
Sensor
|
||||
^^^^^^
|
||||
|
||||
* **1st GPIO**: DL bus input e.g. **GPIO 14 (D5)**
|
||||
* **DL-Bus Type**: **ESR21**
|
||||
|
||||
.. note:: The settings for **1st GPIO** and **DL-Bus Type** must be the same for all used DL bus tasks!
|
||||
|
||||
Inputs
|
||||
^^^^^^
|
||||
|
||||
.. note:: The description of the **Frame data** and the related **Frame bytes** can be found in the section **Protocol**!
|
||||
|
||||
.. csv-table::
|
||||
:header: "Frame data", "Frame bytes", "Value", "Index", "Decimals"
|
||||
:widths: 16, 8, 8, 5, 5
|
||||
|
||||
"Sensor1 ... Sensor3", "3 ... 8", "Sensor", "1 - 3", "1"
|
||||
"Ext1 ... Ext6", "9 ... 20", "Ext. Sensor", "1 - 6", "1"
|
||||
"Output byte", "21", "Digital Output", "", "0"
|
||||
"Speed step", "22", "Speed step", "", "0"
|
||||
"Analog output", "23", "Analog output", "", "1"
|
||||
"Current power", "25,26", "Heat power [kW]", "", "1"
|
||||
"Heat quantity", "27 ... 30", "Heat meter [MWh]", "", "4"
|
||||
|
||||
Data acquisition
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
* **Send to controller** 1..3: Check which controller (if any) you want to publish to. All or no controller can be used.
|
||||
* **Interval**: How often should the task publish its value (10..60 seconds is normal).
|
||||
|
||||
.. note:: Intervall not less than **10 seconds**! The reading of the DL bus happens twice per intervall.
|
||||
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 31 KiB |
@@ -0,0 +1,80 @@
|
||||
.. include:: ../Plugin/_plugin_substitutions_p09x.repl
|
||||
.. _P092_UVR1611_page:
|
||||
|
||||
UVR1611
|
||||
=======
|
||||
|
||||
|P092_typename|
|
||||
|P092_status|
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
The UVR1611 unit is a freely programmable universal control system.
|
||||
The UVR1611 universal controller can be freely programmed using function modules to match any system configuration for heating room management.
|
||||
|
||||
The DL bus runs at 12 volts.
|
||||
The data frame consist of 63 bytes (excluding sync and CRC).
|
||||
The data are transmitted @ 488Hz, therefore the transmission of one data set takes about 1.4 seconds.
|
||||
.. image:: P092_UVR1611.png
|
||||
|
||||
Wiring
|
||||
------
|
||||
|
||||
.. image:: P092_12V_Wiring.png
|
||||
|
||||
Protocol
|
||||
--------
|
||||
|
||||
.. image:: P092_UVR1611_Protocol.png
|
||||
|
||||
Setup
|
||||
-----
|
||||
|
||||
.. note:: A new device task must be created for each value to be read from the DL bus!
|
||||
|
||||
.. image:: P092_Setup.png
|
||||
|
||||
Task settings
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
* **Device**: Heating - DL-Bus (Technische Alternative)
|
||||
* **Name**: Name of the task (example name **ValueN**, where N is a number).
|
||||
* **Enable**: Should the task be enabled or not
|
||||
|
||||
Sensor
|
||||
^^^^^^
|
||||
|
||||
* **1st GPIO**: DL bus input e.g. **GPIO 14 (D5)**
|
||||
* **DL-Bus Type**: **UVR1611**
|
||||
|
||||
.. note:: The settings for **1st GPIO** and **DL-Bus Type** must be the same for all used DL bus tasks!
|
||||
|
||||
Inputs
|
||||
^^^^^^
|
||||
|
||||
.. note:: The description of the **Frame data** and the related **Frame bytes** can be found in the section **Protocol**!
|
||||
|
||||
.. csv-table::
|
||||
:header: "Frame data", "Frame bytes", "Value", "Index", "Decimals"
|
||||
:widths: 16, 8, 8, 5, 5
|
||||
|
||||
"Sensor1 ... Sensor16", "9 ... 40", "Sensor", "1 - 16", "1"
|
||||
"Output A1 ... A7", "41", "Digital Output", "1 - 7", "0"
|
||||
"Output A9 ... A13", "42", "Digital Output", "9 - 13", "0"
|
||||
"Speed step A1", "43", "Speed step", "1", "0"
|
||||
"Speed step A2", "44", "Speed step", "2", "0"
|
||||
"Speed step A6", "45", "Speed step", "3", "0"
|
||||
"Speed step A7", "46", "Speed step", "4", "0"
|
||||
"Current power 1", "48 ... 51", "Heat power [kW]", "1", "2"
|
||||
"Current power 2", "56 ... 59", "Heat power [kW]", "2", "2"
|
||||
"Heat quantity 1", "52 ... 55", "Heat meter [MWh]", "1", "4"
|
||||
"Heat quantity 2", "60 ... 64", "Heat meter [MWh]", "2", "4"
|
||||
|
||||
Data acquisition
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
* **Send to controller** 1..3: Check which controller (if any) you want to publish to. All or no controller can be used.
|
||||
* **Interval**: How often should the task publish its value (10..60 seconds is normal).
|
||||
|
||||
.. note:: Intervall not less than **10 seconds**! The reading of the DL bus happens twice per intervall.
|
||||
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 27 KiB |
@@ -0,0 +1,71 @@
|
||||
.. include:: ../Plugin/_plugin_substitutions_p09x.repl
|
||||
.. _P092_UVR31_page:
|
||||
|
||||
UVR31
|
||||
=====
|
||||
|
||||
|P092_typename|
|
||||
|P092_status|
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
The UVR31 unit is a single-circuit universal control system.
|
||||
The UVR31 unit is designed for simple solar installations and heating systems (storage charging, domestic hot water preparation)
|
||||
|
||||
The DL bus runs at 24 volts.
|
||||
The data frame consist of 8 bytes (excluding sync).
|
||||
The data are transmitted @ 50Hz, therefore the transmission of one data set takes about 1.92 seconds.
|
||||
.. image:: P092_UVR31.png
|
||||
|
||||
Wiring
|
||||
------
|
||||
|
||||
.. image:: P092_24V_Wiring.png
|
||||
|
||||
Protocol
|
||||
--------
|
||||
|
||||
.. image:: P092_UVR31_Protocol.png
|
||||
|
||||
Setup
|
||||
-----
|
||||
|
||||
.. note:: A new device task must be created for each value to be read from the DL bus!
|
||||
|
||||
.. image:: P092_Setup.png
|
||||
|
||||
Task settings
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
* **Device**: Heating - DL-Bus (Technische Alternative)
|
||||
* **Name**: Name of the task (example name **ValueN**, where N is a number).
|
||||
* **Enable**: Should the task be enabled or not
|
||||
|
||||
Sensor
|
||||
^^^^^^
|
||||
|
||||
* **1st GPIO**: DL bus input e.g. **GPIO 14 (D5)**
|
||||
* **DL-Bus Type**: **UVR31**
|
||||
|
||||
.. note:: The settings for **1st GPIO** and **DL-Bus Type** must be the same for all used DL bus tasks!
|
||||
|
||||
Inputs
|
||||
^^^^^^
|
||||
|
||||
.. note:: The description of the **Frame data** and the related **Frame bytes** can be found in the section **Protocol**!
|
||||
|
||||
.. csv-table::
|
||||
:header: "Frame data", "Frame bytes", "Value", "Index", "Decimals"
|
||||
:widths: 16, 8, 8, 5, 5
|
||||
|
||||
"Temp1 ... Temp3", "2 ... 7", "Sensor", "1 - 3", "1"
|
||||
"Output byte", "8", "Digital Output", "", "0"
|
||||
|
||||
Data acquisition
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
* **Send to controller** 1..3: Check which controller (if any) you want to publish to. All or no controller can be used.
|
||||
* **Interval**: How often should the task publish its value (20..60 seconds is normal).
|
||||
|
||||
.. note:: Intervall not less than **20 seconds**! The reading of the DL bus happens twice per intervall.
|
||||
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 78 KiB |
@@ -0,0 +1,76 @@
|
||||
.. include:: ../Plugin/_plugin_substitutions_p09x.repl
|
||||
.. _P092_UVR61-3_page:
|
||||
|
||||
UVR61-3
|
||||
=======
|
||||
|
||||
|P092_typename|
|
||||
|P092_status|
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
The UVR61-3 unit is a three-circuit universal control system.
|
||||
The UVR61-3 unit is designed for an energy-saving and cost-effective drying of cellars and other parts of buildings by means of fan control.
|
||||
The UVR61-3 three-circuit controllers has various thermostat, differential temperature and speed control functions for use in solar and heating systems, too.
|
||||
|
||||
The DL bus runs at 12 volts.
|
||||
The data frame consist of 34 bytes (excluding sync and CRC).
|
||||
The data are transmitted @ 488Hz, therefore the transmission of one data set takes about 0.8 seconds.
|
||||
.. image:: P092_UVR61-3.png
|
||||
|
||||
Wiring
|
||||
------
|
||||
|
||||
.. image:: P092_12V_Wiring.png
|
||||
|
||||
Protocol
|
||||
--------
|
||||
|
||||
.. image:: P092_UVR61-3_Protocol.png
|
||||
|
||||
Setup
|
||||
-----
|
||||
|
||||
.. note:: A new device task must be created for each value to be read from the DL bus!
|
||||
|
||||
.. image:: P092_Setup.png
|
||||
|
||||
Task settings
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
* **Device**: Heating - DL-Bus (Technische Alternative)
|
||||
* **Name**: Name of the task (example name **ValueN**, where N is a number).
|
||||
* **Enable**: Should the task be enabled or not
|
||||
|
||||
Sensor
|
||||
^^^^^^
|
||||
|
||||
* **1st GPIO**: DL bus input e.g. **GPIO 14 (D5)**
|
||||
* **DL-Bus Type**: **UVR61-3 v8.2**
|
||||
|
||||
.. note:: The settings for **1st GPIO** and **DL-Bus Type** must be the same for all used DL bus tasks!
|
||||
|
||||
Inputs
|
||||
^^^^^^
|
||||
|
||||
.. note:: The description of the **Frame data** and the related **Frame bytes** can be found in the section **Protocol**!
|
||||
|
||||
.. csv-table::
|
||||
:header: "Frame data", "Frame bytes", "Value", "Index", "Decimals"
|
||||
:widths: 16, 8, 8, 5, 5
|
||||
|
||||
"Sensor1 ... Sensor6", "9 ... 20", "Sensor", "1 - 6", "1"
|
||||
"Output A1 ... A3", "21", "Digital Output", "1 - 3", "0"
|
||||
"Speed step", "22", "Speed step", "", "0"
|
||||
"Analog output", "23", "Analog output", "", "1"
|
||||
"Current power", "27,28", "Heat power [kW]", "", "1"
|
||||
"Heat quantity", "29 ... 34", "Heat meter [MWh]", "", "4"
|
||||
|
||||
Data acquisition
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
* **Send to controller** 1..3: Check which controller (if any) you want to publish to. All or no controller can be used.
|
||||
* **Interval**: How often should the task publish its value (10..60 seconds is normal).
|
||||
|
||||
.. note:: Intervall not less than **10 seconds**! The reading of the DL bus happens twice per intervall.
|
||||
|
After Width: | Height: | Size: 18 KiB |
@@ -114,6 +114,7 @@ There's three different released versions of ESP Easy:
|
||||
":ref:`P088_page`","|P088_status|","P088"
|
||||
":ref:`P089_page`","|P089_status|","P089"
|
||||
":ref:`P090_page`","|P090_status|","P090"
|
||||
":ref:`P092_page`","|P092_status|","P092"
|
||||
|
||||
|
||||
Internal GPIO handling
|
||||
|
||||
@@ -8,4 +8,15 @@
|
||||
.. |P090_shortinfo| replace:: `.`
|
||||
.. |P090_maintainer| replace:: `TD-er`
|
||||
.. |P090_compileinfo| replace:: `.`
|
||||
.. |P090_usedlibraries| replace:: `.`
|
||||
.. |P090_usedlibraries| replace:: `.`
|
||||
.. |P092_name| replace:: :cyan:`DL-Bus (Technische Alternative)`
|
||||
.. |P092_type| replace:: :cyan:`Heating`
|
||||
.. |P092_typename| replace:: :cyan:`Heating - DL-Bus (Technische Alternative)`
|
||||
.. |P092_status| replace:: :yellow:`TESTING`
|
||||
.. |P092_github| replace:: P092_DLbus.ino
|
||||
.. _P092_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P092_DLbus.ino
|
||||
.. |P092_usedby| replace:: `.`
|
||||
.. |P092_shortinfo| replace:: `.`
|
||||
.. |P092_maintainer| replace:: `.`
|
||||
.. |P092_compileinfo| replace:: `.`
|
||||
.. |P092_usedlibraries| replace:: `.`
|
||||
|
||||
@@ -0,0 +1,372 @@
|
||||
#include "DLBus.h"
|
||||
//
|
||||
// DLBus reads and decodes the DL-Bus.
|
||||
// The DL-Bus is used in heating control units e.g. sold by Technische Alternative (www.ta.co.at).
|
||||
// Author uwekaditz
|
||||
|
||||
//#define DLbus_DEBUG
|
||||
|
||||
// Flags for pulse width (bit 0 is the content!)
|
||||
#define DLbus_FlagSingleWidth 0x02
|
||||
#define DLbus_FlagDoubleWidth 0x04
|
||||
#define DLbus_FlagShorterThanSingleWidth 0x10
|
||||
#define DLbus_FlagBetweenDoubleSingleWidth 0x20
|
||||
#define DLbus_FlagLongerThanDoubleWidth 0x40
|
||||
#define DLbus_FlagLongerThanTwiceDoubleWidth 0x80
|
||||
#define DLbus_FlagsWrongTiming (DLbus_FlagLongerThanTwiceDoubleWidth | DLbus_FlagLongerThanDoubleWidth | DLbus_FlagBetweenDoubleSingleWidth | DLbus_FlagShorterThanSingleWidth)
|
||||
|
||||
extern long usecPassedSince(unsigned long timestamp) ICACHE_RAM_ATTR;
|
||||
extern void addToLog(byte loglevel, const String& string);
|
||||
|
||||
//#define LOG_LEVEL_ERROR 1
|
||||
#define LOG_LEVEL_INFO 2
|
||||
#ifndef F
|
||||
// Create a no-op F() macro so the code base still compiles outside of the
|
||||
// Arduino framework. Thus we can safely use the Arduino 'F()' macro through-out
|
||||
// the code base. That macro stores constants in Flash (PROGMEM) memory.
|
||||
// See: https://github.com/crankyoldgit/IRremoteESP8266/issues/667
|
||||
#define F(x) x
|
||||
#endif // F
|
||||
|
||||
// Helper for ISR call
|
||||
DLBus* DLBus::__instance = nullptr;
|
||||
volatile static uint8_t* ISR_PtrChangeBitStream = nullptr; // pointer to received bit change stream
|
||||
|
||||
DLBus::DLBus()
|
||||
{
|
||||
if (__instance == nullptr)
|
||||
{
|
||||
__instance = this;
|
||||
ISR_PtrChangeBitStream = DLbus_ChangeBitStream;
|
||||
addToLog(LOG_LEVEL_INFO, F("Class DLBus created"));
|
||||
}
|
||||
}
|
||||
|
||||
DLBus::~DLBus()
|
||||
{
|
||||
if (__instance == this)
|
||||
{
|
||||
__instance = nullptr;
|
||||
ISR_PtrChangeBitStream = nullptr;
|
||||
addToLog(LOG_LEVEL_INFO, F("Class DLBus destroyed"));
|
||||
}
|
||||
}
|
||||
|
||||
void DLBus::AddToInfoLog(const String& string)
|
||||
{
|
||||
if ((IsLogLevelInfo) && (LogLevelInfo != 0xff))
|
||||
addToLog(LogLevelInfo, string);
|
||||
}
|
||||
|
||||
void DLBus::AddToErrorLog(const String& string)
|
||||
{
|
||||
if (LogLevelError != 0xff)
|
||||
addToLog(LogLevelError, string);
|
||||
}
|
||||
|
||||
void DLBus::attachDLBusInterrupt(void)
|
||||
{
|
||||
ISR_Receiving = false;
|
||||
attachInterrupt(digitalPinToInterrupt(ISR_DLB_Pin), ISR, CHANGE);
|
||||
}
|
||||
|
||||
void DLBus::StartReceiving(void)
|
||||
{
|
||||
noInterrupts (); // make sure we don't get interrupted before we are ready
|
||||
ISR_PulseCount = 0;
|
||||
ISR_Receiving = (ISR_PtrChangeBitStream != nullptr);
|
||||
ISR_AllBitsReceived = false;
|
||||
interrupts (); // interrupts allowed now, next instruction WILL be executed
|
||||
}
|
||||
|
||||
void ICACHE_RAM_ATTR DLBus::ISR(void)
|
||||
{
|
||||
if (__instance)
|
||||
{
|
||||
__instance->ISR_PinChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void ICACHE_RAM_ATTR DLBus::ISR_PinChanged(void)
|
||||
{
|
||||
long TimeDiff = usecPassedSince(ISR_TimeLastBitChange); // time difference to previous pulse in µs
|
||||
ISR_TimeLastBitChange = micros(); // save last pin change time
|
||||
if (ISR_Receiving) {
|
||||
uint8_t val = digitalRead(ISR_DLB_Pin); // read state
|
||||
// check pulse width
|
||||
if (TimeDiff >= 2*ISR_MinDoublePulseWidth) val |= DLbus_FlagLongerThanTwiceDoubleWidth; // longer then 2x double pulse width
|
||||
else if (TimeDiff > ISR_MaxDoublePulseWidth) val |= DLbus_FlagLongerThanDoubleWidth; // longer then double pulse width
|
||||
else if (TimeDiff >= ISR_MinDoublePulseWidth) val |= DLbus_FlagDoubleWidth; // double pulse width
|
||||
else if (TimeDiff > ISR_MaxPulseWidth) val |= DLbus_FlagBetweenDoubleSingleWidth; // between double and single pulse width
|
||||
else if (TimeDiff < ISR_MinPulseWidth) val |= DLbus_FlagShorterThanSingleWidth; // shorter then single pulse width
|
||||
else val |= DLbus_FlagSingleWidth; // single pulse width
|
||||
if (ISR_PulseCount < 2) {
|
||||
// check if sync is received
|
||||
if (val & DLbus_FlagLongerThanTwiceDoubleWidth) {
|
||||
// sync received
|
||||
*ISR_PtrChangeBitStream = !(val & 0x01);
|
||||
*(ISR_PtrChangeBitStream+1) = val;
|
||||
ISR_PulseCount = 2;
|
||||
}
|
||||
else
|
||||
ISR_PulseCount = 1; // flag that interrupt is receiving
|
||||
}
|
||||
else {
|
||||
*(ISR_PtrChangeBitStream+ISR_PulseCount) = val; // set bit
|
||||
ISR_PulseCount++;
|
||||
ISR_Receiving = (ISR_PulseCount < ISR_PulseNumber); // stop P092_receiving when data frame is complete
|
||||
ISR_AllBitsReceived = !ISR_Receiving;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean DLBus::CheckTimings(void) {
|
||||
uint8_t rawval, val;
|
||||
uint8_t WrongTimeCnt = 0;
|
||||
int i;
|
||||
#ifdef DLbus_DEBUG
|
||||
uint16_t WrongTimingArray[5][6];
|
||||
#endif // DLbus_DEBUG
|
||||
|
||||
// AddToInfoLog(F("Receive stopped."));
|
||||
|
||||
ISR_PulseCount = 0;
|
||||
for (i = 0; i <= ISR_PulseNumber; i++) {
|
||||
// store DLbus_ChangeBitStream into ByteStream
|
||||
rawval = *(ISR_PtrChangeBitStream+i);
|
||||
if (rawval & DLbus_FlagsWrongTiming) {
|
||||
// wrong DLbus_time_diff
|
||||
if (ISR_PulseCount > 0) {
|
||||
#ifdef DLbus_DEBUG
|
||||
WrongTimingArray[WrongTimeCnt][0] = i;
|
||||
WrongTimingArray[WrongTimeCnt][1] = ISR_PulseCount;
|
||||
WrongTimingArray[WrongTimeCnt][2] = BitNumber;
|
||||
WrongTimingArray[WrongTimeCnt][3] = rawval;
|
||||
#endif // DLbus_DEBUG
|
||||
if ((rawval == DLbus_FlagLongerThanTwiceDoubleWidth) && (*(ISR_PtrChangeBitStream+i-1) == (DLbus_FlagDoubleWidth | 0x01))) {
|
||||
// Add two additional short pulses (low and high), previous bit is High and contains DLbus_FlagDoubleWidth
|
||||
ProcessBit(0);
|
||||
ProcessBit(1);
|
||||
#ifdef DLbus_DEBUG
|
||||
WrongTimingArray[WrongTimeCnt][4] = DLbus_FlagSingleWidth;
|
||||
WrongTimingArray[WrongTimeCnt][5] = DLbus_FlagSingleWidth+1;
|
||||
#endif // DLbus_DEBUG
|
||||
}
|
||||
#ifdef DLbus_DEBUG
|
||||
else {
|
||||
WrongTimingArray[WrongTimeCnt][4] = 0xff;
|
||||
WrongTimingArray[WrongTimeCnt][5] = 0xff;
|
||||
}
|
||||
#endif // DLbus_DEBUG
|
||||
WrongTimeCnt++;
|
||||
if (WrongTimeCnt >=5)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
val = rawval & 0x01;
|
||||
if ((rawval & DLbus_FlagDoubleWidth) == DLbus_FlagDoubleWidth) {
|
||||
// double pulse width
|
||||
ProcessBit(!val);
|
||||
ProcessBit(val);
|
||||
}
|
||||
else {
|
||||
// single pulse width
|
||||
ProcessBit(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
// AddToInfoLog(F("DLbus_ChangeBitStream copied."));
|
||||
|
||||
#ifdef DLbus_DEBUG
|
||||
if (WrongTimeCnt > 0) {
|
||||
if (IsLogLevelInfo) {
|
||||
String log = F("Wrong Timings: ");
|
||||
AddToInfoLog(log);
|
||||
for (i = 0; i < WrongTimeCnt; i++) {
|
||||
log = i + 1;
|
||||
log += F(": PulseCount:");
|
||||
log += WrongTimingArray[i][1];
|
||||
log += F(": BitCount:");
|
||||
log += WrongTimingArray[i][2];
|
||||
log += F(" Value:0x");
|
||||
log += String(WrongTimingArray[i][3], HEX);
|
||||
log += F(" ValueBefore:0x");
|
||||
log += String(*(ISR_PtrChangeBitStream+WrongTimingArray[i][0] - 1), HEX);
|
||||
log += F(" ValueAfter:0x");
|
||||
log += String(*(ISR_PtrChangeBitStream+WrongTimingArray[i][0] + 1), HEX);
|
||||
if (WrongTimingArray[i][4]!=0xff) {
|
||||
log += F(" Added:0x");
|
||||
log += String(WrongTimingArray[i][4], HEX);
|
||||
}
|
||||
if (WrongTimingArray[i][5]!=0xff) {
|
||||
log += F(" Added:0x");
|
||||
log += String(WrongTimingArray[i][5], HEX);
|
||||
}
|
||||
AddToInfoLog(log);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // DLbus_DEBUG
|
||||
return true;
|
||||
}
|
||||
|
||||
void DLBus::ProcessBit(uint8_t b) {
|
||||
// ignore first pulse
|
||||
ISR_PulseCount++;
|
||||
if (ISR_PulseCount % 2)
|
||||
return;
|
||||
BitNumber = (ISR_PulseCount / 2);
|
||||
if (b)
|
||||
ByteStream[BitNumber / 8] |= (1 << (BitNumber % 8)); // set bit
|
||||
else
|
||||
ByteStream[BitNumber / 8] &= ~(1 << (BitNumber % 8)); // clear bit
|
||||
}
|
||||
|
||||
boolean DLBus::Processing(void) {
|
||||
boolean inverted = false;
|
||||
int16_t StartBit; // first bit of data frame (-1 not recognized)
|
||||
String log;
|
||||
AddToInfoLog(F("Processing..."));
|
||||
StartBit = Analyze(); // find the data frame's beginning
|
||||
// inverted signal?
|
||||
while (StartBit == -1) {
|
||||
if (inverted) {
|
||||
AddToErrorLog(F("Error: Already inverted!"));
|
||||
return false;
|
||||
}
|
||||
Invert(); // invert again
|
||||
inverted = true;
|
||||
StartBit = Analyze();
|
||||
if (StartBit == -1) {
|
||||
AddToErrorLog(F("Error: No data frame available!"));
|
||||
return false;
|
||||
}
|
||||
uint16_t RequiredBitStreamLength = (ISR_PulseNumber - DLBus_ReserveBytes)/DLBus_BitChangeFactor;
|
||||
if ((BitNumber-StartBit) < RequiredBitStreamLength) {
|
||||
// no complete data frame available (difference between start_bit and received bits is < RequiredBitStreamLength)
|
||||
AddToErrorLog(F("Start bit too close to end of stream!"));
|
||||
if (IsLogLevelInfo) {
|
||||
log = F("# Required bits: ");
|
||||
log += RequiredBitStreamLength;
|
||||
log += F(" StartBit: ");
|
||||
log += StartBit;
|
||||
log += F(" / EndBit: ");
|
||||
log += BitNumber;
|
||||
AddToInfoLog(log);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsLogLevelInfo) {
|
||||
log = F("StartBit: ");
|
||||
log += StartBit;
|
||||
log += F(" / EndBit: ");
|
||||
log += BitNumber;
|
||||
AddToInfoLog(log);
|
||||
}
|
||||
Trim(StartBit); // remove start and stop bits
|
||||
|
||||
if (CheckDevice()) // check connected device
|
||||
return true;
|
||||
else {
|
||||
AddToErrorLog(F("Error: Device not found!"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int DLBus::Analyze(void) {
|
||||
uint8_t sync=0;
|
||||
// find SYNC (16 * sequential 1)
|
||||
for (int i = 0; i < BitNumber; i++) {
|
||||
if (ReadBit(i))
|
||||
sync++;
|
||||
else
|
||||
sync = 0;
|
||||
if (sync == DLBus_SyncBits) {
|
||||
// finde erste 0 // find first 0
|
||||
while (ReadBit(i) == 1)
|
||||
i++;
|
||||
return i; // beginning of data frame
|
||||
}
|
||||
}
|
||||
// no data frame available. check signal?
|
||||
return -1;
|
||||
}
|
||||
|
||||
void DLBus::Invert(void) {
|
||||
AddToInfoLog(F("Invert bit stream..."));
|
||||
for (int i = 0; i < BitNumber; i++)
|
||||
WriteBit(i, ReadBit(i) ? 0 : 1); // invert every bit
|
||||
}
|
||||
|
||||
uint8_t DLBus::ReadBit(int pos) {
|
||||
int row = pos / 8; // detect position in bitmap
|
||||
int col = pos % 8;
|
||||
return (((ByteStream[row]) >> (col)) & 0x01); // return bit
|
||||
}
|
||||
|
||||
void DLBus::WriteBit(int pos, uint8_t set) {
|
||||
int row = pos / 8; // detect position in bitmap
|
||||
int col = pos % 8;
|
||||
if (set)
|
||||
ByteStream[row] |= 1 << col; // set bit
|
||||
else
|
||||
ByteStream[row] &= ~(1 << col); // clear bit
|
||||
}
|
||||
|
||||
void DLBus::Trim(int start_bit) {
|
||||
for (int i = start_bit, bit = 0; i < BitNumber; i++) {
|
||||
int offset = i - start_bit;
|
||||
// ignore start and stop bits:
|
||||
// start bits: 0 10 20 30, also x % 10 == 0
|
||||
// stop bits: 9 19 29 39, also (x+1) % 10 == 0
|
||||
if (offset % 10 && (offset + 1) % 10) {
|
||||
WriteBit(bit, ReadBit(i));
|
||||
bit++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean DLBus::CheckDevice(void) {
|
||||
// Data frame of a device?
|
||||
if (ByteStream[0] == DeviceBytes[0]) {
|
||||
if ((DeviceBytes[1] == 0) || (ByteStream[1] == DeviceBytes[1]))
|
||||
return true;
|
||||
}
|
||||
if (IsLogLevelInfo) {
|
||||
String log = F("# Received DeviceByte(s): 0x");
|
||||
log += String(ByteStream[0], HEX);
|
||||
if (DeviceBytes[1] != 0)
|
||||
log += String(ByteStream[1], HEX);
|
||||
log += F(" Requested: 0x");
|
||||
log += String(DeviceBytes[0], HEX);
|
||||
if (DeviceBytes[1] != 0)
|
||||
log += String(DeviceBytes[1], HEX);
|
||||
AddToInfoLog(log);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean DLBus::CheckCRC(uint8_t IdxCRC) {
|
||||
// CRC check sum
|
||||
if (IdxCRC == 0)
|
||||
return true;
|
||||
AddToInfoLog(F("Check CRC..."));
|
||||
uint16_t dataSum = 0;
|
||||
for (int i = 0; i < IdxCRC; i++)
|
||||
dataSum = dataSum + ByteStream[i];
|
||||
dataSum = dataSum & 0xff;
|
||||
if (dataSum == ByteStream[IdxCRC])
|
||||
return true;
|
||||
AddToErrorLog(F("Check CRC failed!"));
|
||||
if (IsLogLevelInfo) {
|
||||
String log = F("# Calculated CRC: 0x");
|
||||
log += String(dataSum, HEX);
|
||||
log += F(" Received: 0x");
|
||||
log += String(ByteStream[IdxCRC], HEX);
|
||||
AddToInfoLog(log);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
#ifndef DLBus_H
|
||||
#define DLBus_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
/*********************************************************************************************\
|
||||
DLBus subs to get values from the receiving bitstream
|
||||
\*********************************************************************************************/
|
||||
// one data frame has <P092_DataSettings.DataBytes> data bytes + SYNC, e.g. 64 * (8+1+1) + 16 = 656
|
||||
// 656 * 2 = 1312 (twice as much as a data frame is saved
|
||||
// so there's one complete data frame
|
||||
|
||||
#define DLbus_MaxDataBytes 64
|
||||
#define DLbus_AdditionalRecBytes 2
|
||||
#define DLbus_StopBits 1
|
||||
#define DLbus_StartBits 1
|
||||
#define DLBus_SyncBits 16
|
||||
#define DLBus_ReserveBytes 20
|
||||
#define DLBus_BitChangeFactor 2
|
||||
#define DLbus_MaxDataBits (((DLbus_MaxDataBytes + DLbus_AdditionalRecBytes) * (DLbus_StartBits + 8 + DLbus_StopBits) + DLBus_SyncBits) * DLBus_BitChangeFactor) + DLBus_ReserveBytes
|
||||
// MaxDataBits is double of the maximum bit length because each bit change is stored
|
||||
// (((64+2) * (8+1+1) + 16) * 2) + 50 = 1402 bytes
|
||||
|
||||
class DLBus
|
||||
{
|
||||
public:
|
||||
DLBus(); // constructor of DLBus object
|
||||
~DLBus(); // destructor of DLBus object
|
||||
|
||||
volatile uint8_t ISR_DLB_Pin = 0xFF;
|
||||
volatile boolean ISR_Receiving = false; // receiving flag
|
||||
volatile boolean ISR_AllBitsReceived = false;
|
||||
volatile uint16_t ISR_PulseCount; // number of received pulses
|
||||
volatile uint16_t ISR_PulseNumber; // max naumber of the received pulses
|
||||
volatile uint16_t ISR_MinPulseWidth, ISR_MaxPulseWidth, ISR_MinDoublePulseWidth, ISR_MaxDoublePulseWidth;
|
||||
// identification bytes for each DL bus device
|
||||
uint8_t DeviceBytes[2];
|
||||
uint8_t ByteStream[DLbus_MaxDataBits / 8 + 1]; // every bit gets sorted into a bitmap
|
||||
boolean IsLogLevelInfo = false;
|
||||
uint8_t LogLevelInfo = 0xff;
|
||||
uint8_t LogLevelError = 0xFF;
|
||||
void attachDLBusInterrupt(void);
|
||||
void StartReceiving(void);
|
||||
boolean CheckTimings(void);
|
||||
boolean Processing(void);
|
||||
boolean CheckCRC(uint8_t IdxCRC);
|
||||
private:
|
||||
volatile uint32_t ISR_TimeLastBitChange = 0; // remember time of last transition
|
||||
uint8_t DLbus_ChangeBitStream[DLbus_MaxDataBits]; // received bit change stream (each bit change is extended to uint8_t, containing the timing flags)
|
||||
uint16_t BitNumber; // bit number of the received DLbus_ChangeBitStream
|
||||
static void ISR(void);
|
||||
void ISR_PinChanged(void);
|
||||
void ProcessBit(uint8_t b);
|
||||
int Analyze(void);
|
||||
void Invert(void);
|
||||
uint8_t ReadBit(int pos);
|
||||
void WriteBit(int pos, uint8_t set);
|
||||
void Trim(int start_bit);
|
||||
boolean CheckDevice(void);
|
||||
static DLBus* __instance;
|
||||
void AddToInfoLog(const String& string);
|
||||
void AddToErrorLog(const String& string);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,6 @@
|
||||
DLBus KEYWORD1
|
||||
attachDLBusInterrupt KEYWORD2
|
||||
StartReceiving KEYWORD2
|
||||
CheckTimings KEYWORD2
|
||||
Processing KEYWORD2
|
||||
CheckCRC KEYWORD2
|
||||
@@ -81,7 +81,7 @@
|
||||
// BMP280 I2C Barometric Pressure sensor
|
||||
// SHT1X temperature/humidity sensors
|
||||
// Ser2Net server
|
||||
|
||||
// DL-Bus (Technische Alternative)
|
||||
|
||||
// Define globals before plugin sets to allow a personal override of the selected plugins
|
||||
#include "ESPEasy-Globals.h"
|
||||
|
||||
@@ -0,0 +1,947 @@
|
||||
#ifdef USES_P092
|
||||
|
||||
//#######################################################################################################
|
||||
//########################### Plugin 092: DL-bus from Technische Alternative ############################
|
||||
//#######################################################################################################
|
||||
|
||||
/**************************************************\
|
||||
This plug-in reads and decodes the DL-Bus.
|
||||
The DL-Bus is used in heating control units e.g. sold by Technische Alternative (www.ta.co.at).
|
||||
|
||||
The idea for this plug-in is based on Martin Kropf's project UVR31_RF24 (https://github.com/martinkropf/UVR31_RF24)
|
||||
|
||||
The plug-in is tested and workis fine for the ESR21 device.
|
||||
The plug-in should be also able to decode the information from the
|
||||
UVR31, UVR1611 and UVR 61-3 devices.
|
||||
|
||||
The selected input needs a voltage divider as follows because the DL-Bus runs on 12 volts for
|
||||
following devices: UVR31, UVR42, UVR64, HZR65, EEG30 and TFM66
|
||||
DLbus@12V - 8k6 - input@3.3V - 3k3 - ground
|
||||
|
||||
For following devices just a pull up resistor is needed if the device is used stand alone:
|
||||
UVR1611, UVR61-3 and ESR21
|
||||
|
||||
@uwekaditz 2020-03-01 Memory usage optimized
|
||||
CHG: Moved arrays into the class DLBus
|
||||
CHG: Moved arrays to PLUGIN_092_DEBUG
|
||||
|
||||
@uwekaditz 2019-12-15 Memory usage optimized
|
||||
CHG: Moved the array for the received bit changes to stativ uint_8t, the ISR call uses only a volatile pointer to it
|
||||
CHG: some more defines and name changes for better explanation
|
||||
|
||||
@uwekaditz 2019-12-14 Timing optimized
|
||||
CHG: Removed the while (P092_receiving) loop.
|
||||
CHG: Starting of the receiving and processing of the received bit stream are now done in the PLUGIN_ONCE_A_SECOND call
|
||||
PLUGIN_READ call just uses the already processed data
|
||||
|
||||
@uwekaditz 2019-12-08 Inital commit to mega
|
||||
|
||||
\**************************************************/
|
||||
|
||||
#include <DLBus.h>
|
||||
|
||||
#define PLUGIN_092
|
||||
#define PLUGIN_ID_092 92
|
||||
//#define PLUGIN_092_DEBUG // additional debug messages in the log
|
||||
#define PLUGIN_NAME_092 "Heating - DL-Bus (Technische Alternative)"
|
||||
#define PLUGIN_VALUENAME1_092 "Value"
|
||||
|
||||
#define P092_DLbus_OptionCount 8
|
||||
#define P092_DLbus_ValueCount 1
|
||||
#define P092_DLbus_DeviceCount 5
|
||||
|
||||
uint8_t P092_Last_DLB_Pin;
|
||||
boolean P092_init = false;
|
||||
boolean P092_ReceivedOK = false;
|
||||
uint32_t P092_LastReceived = 0;
|
||||
struct _P092_DataStruct
|
||||
{
|
||||
uint8_t DataBytes;
|
||||
uint8_t DeviceByte0;
|
||||
uint8_t DeviceByte1;
|
||||
uint8_t DeviceBytes;
|
||||
uint8_t DontCareBytes;
|
||||
uint8_t TimeStampBytes;
|
||||
uint8_t MaxSensors;
|
||||
uint8_t MaxExtSensors;
|
||||
uint8_t OutputBytes;
|
||||
uint8_t SpeedBytes;
|
||||
uint8_t AnalogBytes;
|
||||
uint8_t VolumeBytes;
|
||||
uint8_t MaxHeatMeters;
|
||||
uint8_t CurrentHmBytes;
|
||||
uint8_t MWhBytes;
|
||||
|
||||
uint16_t DLbus_MinPulseWidth;
|
||||
uint16_t DLbus_MaxPulseWidth;
|
||||
uint16_t DLbus_MinDoublePulseWidth;
|
||||
uint16_t DLbus_MaxDoublePulseWidth;
|
||||
uint8_t IdxSensor;
|
||||
uint8_t IdxExtSensor;
|
||||
uint8_t IdxOutput;
|
||||
uint8_t IdxDrehzahl;
|
||||
uint8_t IdxAnalog;
|
||||
uint8_t IdxHmRegister;
|
||||
uint8_t IdxVolume;
|
||||
uint8_t IdxHeatMeter1;
|
||||
uint8_t IdxkWh1;
|
||||
uint8_t IdxMWh1;
|
||||
uint8_t IdxHeatMeter2;
|
||||
uint8_t IdxkWh2;
|
||||
uint8_t IdxMWh2;
|
||||
uint8_t IdxHeatMeter3;
|
||||
uint8_t IdxkWh3;
|
||||
uint8_t IdxMWh3;
|
||||
uint8_t IdxCRC;
|
||||
} P092_DataSettings;
|
||||
|
||||
typedef struct {
|
||||
uint8_t Idx;
|
||||
uint8_t mode;
|
||||
float value;
|
||||
} sP092_ReadData;
|
||||
|
||||
DLBus *DLbus_Data = nullptr;
|
||||
|
||||
// decoding the manchester code
|
||||
// pulse width @ 488hz: 1000ms/488 = 2,048ms = 2048µs
|
||||
// 2048µs / 2 = 1024µs (2 pulses for one bit)
|
||||
// pulse width @ 50hz: 1000ms/50 = 20ms = 20000µs
|
||||
// 20000µs / 2 = 10000µs (2 pulses for one bit)
|
||||
#define P092_pulse_width_488 1024 // µs
|
||||
#define P092_pulse_width_50 10000 // µs
|
||||
|
||||
// % tolerance for variances at the pulse width
|
||||
#define P092_percentage_variance 10
|
||||
// 1001 or 0110 are two sequential pulses without transition
|
||||
#define P092_double_pulse_width_488 (P092_pulse_width_488 * 2)
|
||||
#define P092_double_pulse_width_50 (P092_pulse_width_50 * 2)
|
||||
|
||||
// calculating the tolerance limits for variances
|
||||
#define P092_min_width_488 (P092_pulse_width_488 - (P092_pulse_width_488 * P092_percentage_variance / 100))
|
||||
#define P092_max_width_488 (P092_pulse_width_488 + (P092_pulse_width_488 * P092_percentage_variance / 100))
|
||||
#define P092_double_min_width_488 (P092_double_pulse_width_488 - (P092_pulse_width_488 * P092_percentage_variance / 100))
|
||||
#define P092_double_max_width_488 (P092_double_pulse_width_488 + (P092_pulse_width_488 * P092_percentage_variance / 100))
|
||||
#define P092_min_width_50 (P092_pulse_width_50 - (P092_pulse_width_50 * P092_percentage_variance / 100))
|
||||
#define P092_max_width_50 (P092_pulse_width_50 + (P092_pulse_width_50 * P092_percentage_variance / 100))
|
||||
#define P092_double_min_width_50 (P092_double_pulse_width_50 - (P092_pulse_width_50 * P092_percentage_variance / 100))
|
||||
#define P092_double_max_width_50 (P092_double_pulse_width_50 + (P092_pulse_width_50 * P092_percentage_variance / 100))
|
||||
|
||||
boolean P092_GetData(int OptionIdx, int CurIdx, sP092_ReadData* ReadData);
|
||||
|
||||
boolean Plugin_092(uint8_t function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
int OptionIdx, CurIdx;
|
||||
sP092_ReadData P092_ReadData;
|
||||
|
||||
uint8_t P092_MaxIdx[P092_DLbus_OptionCount];
|
||||
int P092_ValueType, P092_ValueIdx;
|
||||
int P092_OptionValueDecimals[P092_DLbus_OptionCount] = {
|
||||
// Dezimalstellen der Variablen
|
||||
0, //F("None")
|
||||
1, //[0,1°C] F("Sensor")
|
||||
1, //[0,1°C] F("Ext. sensor")
|
||||
0, // F("Digital output")
|
||||
0, // F("Speed step")
|
||||
1, //[0,1V] F("Analog output")
|
||||
1, //[0,1kW] F("Heat power (kW)") Attention: UVR1611 in 0,01kW
|
||||
4 //[0,0001MWh] F("Heat meter (MWh)")
|
||||
};
|
||||
|
||||
|
||||
const String plugin_092_ValStr = F("p092_Value");
|
||||
const String plugin_092_IdxStr = F("p092_Idx");
|
||||
|
||||
|
||||
switch (function)
|
||||
{
|
||||
case PLUGIN_DEVICE_ADD:
|
||||
{
|
||||
Device[++deviceCount].Number = PLUGIN_ID_092;
|
||||
Device[deviceCount].Type = DEVICE_TYPE_SINGLE;
|
||||
Device[deviceCount].VType = SENSOR_TYPE_SINGLE;
|
||||
Device[deviceCount].Ports = 0;
|
||||
Device[deviceCount].PullUpOption = false;
|
||||
Device[deviceCount].InverseLogicOption = false;
|
||||
Device[deviceCount].FormulaOption = false;
|
||||
Device[deviceCount].ValueCount = P092_DLbus_ValueCount;
|
||||
Device[deviceCount].SendDataOption = true;
|
||||
Device[deviceCount].TimerOption = true;
|
||||
Device[deviceCount].GlobalSyncOption = true;
|
||||
Device[deviceCount].DecimalsOnly = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICENAME:
|
||||
{
|
||||
string = F(PLUGIN_NAME_092);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEVALUENAMES:
|
||||
{
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_092));
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
P092_Last_DLB_Pin = CONFIG_PIN1;
|
||||
|
||||
const String plugin_092_DefValueName = F(PLUGIN_VALUENAME1_092);
|
||||
const int P092_OptionTypes[P092_DLbus_OptionCount] = {
|
||||
// Index der Variablen
|
||||
0, //F("None")
|
||||
1, //F("Sensor")
|
||||
2, //F("Ext. sensor")
|
||||
3, //F("Digital output")
|
||||
4, //F("Speed step")
|
||||
5, //F("Analog output")
|
||||
6, //F("Heat power (kW)")
|
||||
7 //F("Heat meter (MWh)")
|
||||
};
|
||||
const String Options[P092_DLbus_OptionCount] = {
|
||||
F("None"),
|
||||
F("Sensor"),
|
||||
F("Ext. sensor"),
|
||||
F("Digital output"),
|
||||
F("Speed step"),
|
||||
F("Analog output"),
|
||||
F("Heat power (kW)"),
|
||||
F("Heat meter (MWh)")
|
||||
};
|
||||
const String Devices[P092_DLbus_DeviceCount] = { F("ESR21"), F("UVR31"), F("UVR1611"), F("UVR 61-3 (bis V8.2)"), F("UVR 61-3 (ab V8.3)") };
|
||||
const int DevTypes[P092_DLbus_DeviceCount] = { 21, 31, 1611, 6132, 6133 };
|
||||
|
||||
addFormSelector(F("DL-Bus Type"), F("p092_dlbtype"), P092_DLbus_DeviceCount, Devices, DevTypes, NULL, PCONFIG(0), true );
|
||||
|
||||
// Calculation of the max indices for each sensor type
|
||||
// default indizes for UVR31
|
||||
P092_MaxIdx[0] = 0; // None
|
||||
P092_MaxIdx[1] = 3; // Sensor
|
||||
P092_MaxIdx[2] = 0; // Ext. sensor
|
||||
P092_MaxIdx[3] = 1; // Digital output
|
||||
P092_MaxIdx[4] = 0; // Speed step
|
||||
P092_MaxIdx[5] = 0; // Analog output
|
||||
P092_MaxIdx[6] = 0; // Heat power (kW)
|
||||
P092_MaxIdx[7] = 0; // Heat meter (MWh)
|
||||
switch (PCONFIG(0)) {
|
||||
case 21: //ESR21
|
||||
P092_MaxIdx[2] = 6; // Ext. sensor
|
||||
P092_MaxIdx[4] = 1; // Speed step
|
||||
P092_MaxIdx[5] = 1; // Analog output
|
||||
P092_MaxIdx[6] = 1; // Heat power (kW)
|
||||
P092_MaxIdx[7] = 1; // Heat meter (MWh)
|
||||
break;
|
||||
case 1611: //UVR1611
|
||||
P092_MaxIdx[1] = 16; // Sensor
|
||||
P092_MaxIdx[3] = 13; // Digital output
|
||||
P092_MaxIdx[4] = 4; // Speed step
|
||||
P092_MaxIdx[6] = 2; // Heat power (kW)
|
||||
P092_MaxIdx[7] = 2; // Heat meter (MWh)
|
||||
break;
|
||||
case 6132: //UVR 61-3 (bis V8.2)
|
||||
P092_MaxIdx[1] = 6; // Sensor
|
||||
P092_MaxIdx[3] = 8; // Digital output
|
||||
P092_MaxIdx[4] = 1; // Speed step
|
||||
P092_MaxIdx[5] = 1; // Analog output
|
||||
P092_MaxIdx[6] = 1; // Heat power (kW)
|
||||
P092_MaxIdx[7] = 1; // Heat meter (MWh)
|
||||
break;
|
||||
case 6133: //UVR 61-3 (ab V8.3)
|
||||
P092_MaxIdx[1] = 6; // Sensor
|
||||
P092_MaxIdx[2] = 9; // Ext. sensor
|
||||
P092_MaxIdx[3] = 3; // Digital output
|
||||
P092_MaxIdx[4] = 1; // Speed step
|
||||
P092_MaxIdx[5] = 2; // Analog output
|
||||
P092_MaxIdx[6] = 3; // Heat power (kW)
|
||||
P092_MaxIdx[7] = 3; // Heat meter (MWh)
|
||||
break;
|
||||
}
|
||||
|
||||
addFormSubHeader(F("Inputs"));
|
||||
|
||||
for (int i = 0; i < P092_DLbus_ValueCount; i++) {
|
||||
P092_ValueType = PCONFIG(i + 1) >> 8;
|
||||
P092_ValueIdx = PCONFIG(i + 1) & 0x00FF;
|
||||
|
||||
addFormSelector(plugin_092_DefValueName, plugin_092_ValStr, P092_DLbus_OptionCount, Options, P092_OptionTypes, NULL, P092_ValueType, true);
|
||||
if (P092_MaxIdx[P092_ValueType] > 1) {
|
||||
CurIdx = P092_ValueIdx;
|
||||
if (CurIdx < 1) {
|
||||
CurIdx = 1;
|
||||
}
|
||||
if (CurIdx > P092_MaxIdx[P092_ValueType]) {
|
||||
CurIdx = P092_MaxIdx[P092_ValueType];
|
||||
}
|
||||
addHtml(F(" Index: "));
|
||||
addNumericBox(plugin_092_IdxStr, CurIdx, 1, P092_MaxIdx[P092_ValueType]);
|
||||
}
|
||||
}
|
||||
|
||||
UserVar[event->BaseVarIndex] = NAN;
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SAVE:
|
||||
{
|
||||
PCONFIG(0) = getFormItemInt(F("p092_dlbtype"));
|
||||
if (PCONFIG(0) == 1611) // only UVR1611
|
||||
P092_OptionValueDecimals[6] = 2;
|
||||
|
||||
for (int i = 0; i < P092_DLbus_ValueCount; i++) {
|
||||
OptionIdx = getFormItemInt(plugin_092_ValStr);
|
||||
CurIdx = getFormItemInt(plugin_092_IdxStr);
|
||||
if (CurIdx < 1) {
|
||||
CurIdx = 1;
|
||||
}
|
||||
PCONFIG(i + 1) = (OptionIdx << 8) + CurIdx;
|
||||
ExtraTaskSettings.TaskDeviceValueDecimals[event->BaseVarIndex + i] = P092_OptionValueDecimals[OptionIdx];
|
||||
}
|
||||
|
||||
if (DLbus_Data == nullptr) {
|
||||
addLog(LOG_LEVEL_ERROR, F("## P092_save: Error DL-Bus: Class not initialized!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (P092_Last_DLB_Pin != CONFIG_PIN1) {
|
||||
// pin number is changed -> run a new init
|
||||
P092_init = false;
|
||||
if (DLbus_Data->ISR_DLB_Pin != 0xFF) {
|
||||
// interrupt was already attached to P092_DLB_Pin
|
||||
detachInterrupt(digitalPinToInterrupt(DLbus_Data->ISR_DLB_Pin));
|
||||
addLog(LOG_LEVEL_INFO, F("P092_save: detachInterrupt"));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PLUGIN_092_DEBUG
|
||||
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
|
||||
|
||||
String log = F("PLUGIN_WEBFORM_SAVE :");
|
||||
log += F(" DLB_Pin:");
|
||||
log += CONFIG_PIN1;
|
||||
log += F(" DLbus_MinPulseWidth:");
|
||||
log += P092_DataSettings.DLbus_MinPulseWidth;
|
||||
log += F(" DLbus_MaxPulseWidth:");
|
||||
log += P092_DataSettings.DLbus_MaxPulseWidth;
|
||||
log += F(" DLbus_MinDoublePulseWidth:");
|
||||
log += P092_DataSettings.DLbus_MinDoublePulseWidth;
|
||||
log += F(" DLbus_MaxDoublePulseWidth:");
|
||||
log += P092_DataSettings.DLbus_MaxDoublePulseWidth;
|
||||
log += F(" IdxSensor:");
|
||||
log += P092_DataSettings.IdxSensor;
|
||||
log += F(" IdxExtSensor:");
|
||||
log += P092_DataSettings.IdxExtSensor;
|
||||
log += F(" IdxOutput:");
|
||||
log += P092_DataSettings.IdxOutput;
|
||||
if (P092_DataSettings.SpeedBytes > 0) {
|
||||
log += F(" IdxDrehzahl:");
|
||||
log += P092_DataSettings.IdxDrehzahl;
|
||||
}
|
||||
if (P092_DataSettings.AnalogBytes > 0) {
|
||||
log += F(" IdxAnalog:");
|
||||
log += P092_DataSettings.IdxAnalog;
|
||||
}
|
||||
if (P092_DataSettings.MaxHeatMeters > 0) {
|
||||
log += F(" IdxHmRegister:");
|
||||
log += P092_DataSettings.IdxHmRegister;
|
||||
}
|
||||
if (P092_DataSettings.VolumeBytes > 0) {
|
||||
log += F(" IdxVolume:");
|
||||
log += P092_DataSettings.IdxVolume;
|
||||
}
|
||||
if (P092_DataSettings.MaxHeatMeters > 0) {
|
||||
log += F(" IdxHM1:");
|
||||
log += P092_DataSettings.IdxHeatMeter1;
|
||||
log += F(" IdxkWh1:");
|
||||
log += P092_DataSettings.IdxkWh1;
|
||||
log += F(" IdxMWh1:");
|
||||
log += P092_DataSettings.IdxMWh1;
|
||||
}
|
||||
if (P092_DataSettings.MaxHeatMeters > 1) {
|
||||
log += F(" IdxHM2:");
|
||||
log += P092_DataSettings.IdxHeatMeter2;
|
||||
log += F(" IdxkWh2:");
|
||||
log += P092_DataSettings.IdxkWh2;
|
||||
log += F(" IdxMWh2:");
|
||||
log += P092_DataSettings.IdxMWh2;
|
||||
}
|
||||
if (P092_DataSettings.MaxHeatMeters > 2) {
|
||||
log += F(" IdxHM3:");
|
||||
log += P092_DataSettings.IdxHeatMeter3;
|
||||
log += F(" IdxkWh3:");
|
||||
log += P092_DataSettings.IdxkWh3;
|
||||
log += F(" IdxMWh3:");
|
||||
log += P092_DataSettings.IdxMWh3;
|
||||
}
|
||||
log += F(" IdxCRC:");
|
||||
log += P092_DataSettings.IdxCRC;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
}
|
||||
#endif // PLUGIN_092_DEBUG
|
||||
UserVar[event->BaseVarIndex] = NAN;
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
if (P092_init) {
|
||||
addLog(LOG_LEVEL_ERROR, F("P092_init -> Already done!"));
|
||||
}
|
||||
else {
|
||||
addLog(LOG_LEVEL_INFO, F("P092_init ..."));
|
||||
if (DLbus_Data == nullptr) {
|
||||
DLbus_Data = new DLBus;
|
||||
if (DLbus_Data == nullptr) {
|
||||
addLog(LOG_LEVEL_ERROR, F("## P092_init: Error DL-Bus: Class not initialized!"));
|
||||
return false;
|
||||
}
|
||||
DLbus_Data->LogLevelInfo = LOG_LEVEL_INFO;
|
||||
DLbus_Data->LogLevelError = LOG_LEVEL_ERROR;
|
||||
DLbus_Data->IsLogLevelInfo = loglevelActiveFor(LOG_LEVEL_INFO);
|
||||
}
|
||||
P092_init = true;
|
||||
P092_ReceivedOK = false;
|
||||
addLog(LOG_LEVEL_INFO, F("P092_init: attachInterrupt"));
|
||||
DLbus_Data->ISR_DLB_Pin = CONFIG_PIN1;
|
||||
pinMode(CONFIG_PIN1, INPUT_PULLUP);
|
||||
// on a CHANGE on the data pin P092_Pin_changed is called
|
||||
DLbus_Data->attachDLBusInterrupt();
|
||||
UserVar[event->BaseVarIndex] = NAN;
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_ONCE_A_SECOND:
|
||||
{
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
return false;
|
||||
}
|
||||
if (P092_init == false) {
|
||||
return false;
|
||||
}
|
||||
if (DLbus_Data == nullptr)
|
||||
return false;
|
||||
if (DLbus_Data->ISR_Receiving) {
|
||||
return false;
|
||||
}
|
||||
Plugin_092_SetIndices(PCONFIG(0));
|
||||
if (DLbus_Data->ISR_AllBitsReceived) {
|
||||
DLbus_Data->ISR_AllBitsReceived = false;
|
||||
success = DLbus_Data->CheckTimings();
|
||||
if (success)
|
||||
success = DLbus_Data->Processing();
|
||||
if (success)
|
||||
success = DLbus_Data->CheckCRC(P092_DataSettings.IdxCRC);
|
||||
if (success) {
|
||||
addLog(LOG_LEVEL_INFO, F("Received data OK"));
|
||||
P092_LastReceived = millis();
|
||||
}
|
||||
P092_ReceivedOK = success;
|
||||
}
|
||||
else
|
||||
success = P092_ReceivedOK;
|
||||
|
||||
if ((P092_ReceivedOK == false) || (timePassedSince(P092_LastReceived)>(static_cast<long>(Settings.TaskDeviceTimer[event->TaskIndex] * 1000/2)))) {
|
||||
Plugin_092_StartReceiving();
|
||||
success = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_READ:
|
||||
{
|
||||
addLog(LOG_LEVEL_ERROR, F("PLUGIN_092_READ"));
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
// too busy for DLbus while wifi connect is running
|
||||
addLog(LOG_LEVEL_ERROR, F("## P092_read: Error DL-Bus: WiFi not connected!"));
|
||||
return false;
|
||||
}
|
||||
if (P092_init == false) {
|
||||
addLog(LOG_LEVEL_ERROR, F("## P092_read: Error DL-Bus: Not initialized!"));
|
||||
return false;
|
||||
}
|
||||
if (DLbus_Data == nullptr) {
|
||||
addLog(LOG_LEVEL_ERROR, F("## P092_read: Error DL-Bus: Class not initialized!"));
|
||||
return false;
|
||||
}
|
||||
if (DLbus_Data->ISR_DLB_Pin != CONFIG_PIN1) {
|
||||
String log = F("## P092_read: Error DL-Bus: Device Pin setting not correct!");
|
||||
log += F(" DLB_Pin:");
|
||||
log += DLbus_Data->ISR_DLB_Pin;
|
||||
log += F(" Setting:");
|
||||
log += CONFIG_PIN1;
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
return false;
|
||||
}
|
||||
success = P092_ReceivedOK;
|
||||
if (P092_ReceivedOK == false) {
|
||||
addLog(LOG_LEVEL_INFO, F("P092_read: Still receiving DL-Bus bits!"));
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < P092_DLbus_ValueCount; i++) {
|
||||
OptionIdx = PCONFIG(i + 1) >> 8;
|
||||
CurIdx = PCONFIG(i + 1) & 0x00FF;
|
||||
if (P092_GetData(OptionIdx, CurIdx, &P092_ReadData)) {
|
||||
UserVar[event->BaseVarIndex + i] = P092_ReadData.value;
|
||||
}
|
||||
else {
|
||||
addLog(LOG_LEVEL_ERROR, F("## P092_read: Error: No readings!"));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
void Plugin_092_SetIndices(int DeviceIndex) {
|
||||
// Set the indices for the DL bus packet
|
||||
int iDeviceBytes, iDontCareBytes, iTimeStampBytes;
|
||||
|
||||
//default settings for ESR21
|
||||
P092_DataSettings.DataBytes = 31;
|
||||
P092_DataSettings.DLbus_MinPulseWidth = P092_min_width_488;
|
||||
P092_DataSettings.DLbus_MaxPulseWidth = P092_max_width_488;
|
||||
P092_DataSettings.DLbus_MinDoublePulseWidth = P092_double_min_width_488;
|
||||
P092_DataSettings.DLbus_MaxDoublePulseWidth = P092_double_max_width_488;
|
||||
|
||||
P092_DataSettings.DeviceByte0 = 0x70;
|
||||
P092_DataSettings.DeviceByte1 = 0x8F;
|
||||
iDeviceBytes = 2;
|
||||
iDontCareBytes = 0;
|
||||
iTimeStampBytes = 0;
|
||||
P092_DataSettings.MaxSensors = 3;
|
||||
P092_DataSettings.MaxExtSensors = 6;
|
||||
P092_DataSettings.OutputBytes = 1;
|
||||
P092_DataSettings.SpeedBytes = 1;
|
||||
P092_DataSettings.AnalogBytes = 1;
|
||||
P092_DataSettings.VolumeBytes = 0;
|
||||
P092_DataSettings.MaxHeatMeters = 1;
|
||||
P092_DataSettings.CurrentHmBytes = 2;
|
||||
P092_DataSettings.MWhBytes = 2;
|
||||
P092_DataSettings.IdxCRC = 30;
|
||||
|
||||
switch (DeviceIndex) {
|
||||
case 31: //UVR31
|
||||
P092_DataSettings.DataBytes = 8;
|
||||
P092_DataSettings.DLbus_MinPulseWidth = P092_min_width_50;
|
||||
P092_DataSettings.DLbus_MaxPulseWidth = P092_max_width_50;
|
||||
P092_DataSettings.DLbus_MinDoublePulseWidth = P092_double_min_width_50;
|
||||
P092_DataSettings.DLbus_MaxDoublePulseWidth = P092_double_max_width_50;
|
||||
|
||||
P092_DataSettings.DeviceByte0 = 0x30;
|
||||
P092_DataSettings.DeviceByte1 = 0;
|
||||
iDeviceBytes = 1;
|
||||
P092_DataSettings.MaxExtSensors = 0;
|
||||
P092_DataSettings.SpeedBytes = 0;
|
||||
P092_DataSettings.AnalogBytes = 0;
|
||||
P092_DataSettings.MaxHeatMeters = 0;
|
||||
P092_DataSettings.CurrentHmBytes = 0;
|
||||
P092_DataSettings.MWhBytes = 0;
|
||||
P092_DataSettings.IdxCRC = 0;
|
||||
break;
|
||||
case 1611: //UVR1611
|
||||
P092_DataSettings.DataBytes = 64;
|
||||
|
||||
P092_DataSettings.DeviceByte0 = 0x80;
|
||||
P092_DataSettings.DeviceByte1 = 0x7F;
|
||||
iDontCareBytes = 1;
|
||||
iTimeStampBytes = 5;
|
||||
P092_DataSettings.MaxSensors = 16;
|
||||
P092_DataSettings.MaxExtSensors = 0;
|
||||
P092_DataSettings.OutputBytes = 2;
|
||||
P092_DataSettings.SpeedBytes = 4;
|
||||
P092_DataSettings.AnalogBytes = 0;
|
||||
P092_DataSettings.MaxHeatMeters = 2;
|
||||
P092_DataSettings.CurrentHmBytes = 4;
|
||||
P092_DataSettings.IdxCRC = P092_DataSettings.DataBytes-1;
|
||||
|
||||
break;
|
||||
case 6132: //UVR 61-3 (up to V8.2)
|
||||
P092_DataSettings.DataBytes = 35;
|
||||
|
||||
P092_DataSettings.DeviceByte0 = 0x90;
|
||||
P092_DataSettings.DeviceByte1 = 0x6F;
|
||||
iDontCareBytes = 1;
|
||||
iTimeStampBytes = 5;
|
||||
P092_DataSettings.MaxSensors = 6;
|
||||
P092_DataSettings.MaxExtSensors = 0;
|
||||
P092_DataSettings.VolumeBytes = 2;
|
||||
P092_DataSettings.MWhBytes = 4;
|
||||
P092_DataSettings.IdxCRC = P092_DataSettings.DataBytes-1;
|
||||
|
||||
break;
|
||||
case 6133: //UVR 61-3 (from V8.3)
|
||||
P092_DataSettings.DataBytes = 62;
|
||||
|
||||
P092_DataSettings.DeviceByte0 = 0x90;
|
||||
P092_DataSettings.DeviceByte1 = 0x9F;
|
||||
iDontCareBytes = 1;
|
||||
iTimeStampBytes = 5;
|
||||
P092_DataSettings.MaxSensors = 6;
|
||||
P092_DataSettings.MaxExtSensors = 9;
|
||||
P092_DataSettings.MaxHeatMeters = 3;
|
||||
P092_DataSettings.IdxCRC = P092_DataSettings.DataBytes-1;
|
||||
|
||||
break;
|
||||
}
|
||||
P092_DataSettings.IdxSensor = iDeviceBytes + iDontCareBytes + iTimeStampBytes;
|
||||
P092_DataSettings.IdxExtSensor = P092_DataSettings.IdxSensor + 2 * P092_DataSettings.MaxSensors;
|
||||
P092_DataSettings.IdxOutput = P092_DataSettings.IdxExtSensor + 2 * P092_DataSettings.MaxExtSensors;
|
||||
P092_DataSettings.IdxDrehzahl = P092_DataSettings.IdxOutput + P092_DataSettings.OutputBytes;
|
||||
P092_DataSettings.IdxAnalog = P092_DataSettings.IdxDrehzahl + P092_DataSettings.SpeedBytes;
|
||||
P092_DataSettings.IdxHmRegister = P092_DataSettings.IdxAnalog + P092_DataSettings.AnalogBytes;
|
||||
P092_DataSettings.IdxVolume = P092_DataSettings.IdxHmRegister + 1;
|
||||
P092_DataSettings.IdxHeatMeter1 = P092_DataSettings.IdxVolume + P092_DataSettings.VolumeBytes;
|
||||
P092_DataSettings.IdxkWh1 = P092_DataSettings.IdxHeatMeter1 + P092_DataSettings.CurrentHmBytes;
|
||||
P092_DataSettings.IdxMWh1 = P092_DataSettings.IdxkWh1 + 2;
|
||||
P092_DataSettings.IdxHeatMeter2 = P092_DataSettings.IdxMWh1 + P092_DataSettings.MWhBytes;
|
||||
P092_DataSettings.IdxkWh2 = P092_DataSettings.IdxHeatMeter2 + P092_DataSettings.CurrentHmBytes;
|
||||
P092_DataSettings.IdxMWh2 = P092_DataSettings.IdxkWh2 + 2;
|
||||
P092_DataSettings.IdxHeatMeter3 = P092_DataSettings.IdxMWh2 + P092_DataSettings.MWhBytes;
|
||||
P092_DataSettings.IdxkWh3 = P092_DataSettings.IdxHeatMeter3 + P092_DataSettings.CurrentHmBytes;
|
||||
P092_DataSettings.IdxMWh3 = P092_DataSettings.IdxkWh3 + 2;
|
||||
|
||||
return;
|
||||
}
|
||||
/*********************************************************************************************\
|
||||
DLBus subs to get values from the P092_receiving bitstream
|
||||
\*********************************************************************************************/
|
||||
|
||||
// sensor types
|
||||
#define DLbus_UNUSED 0b000
|
||||
#define DLbus_Sensor_DIGITAL 0b001
|
||||
#define DLbus_Sensor_TEMP 0b010
|
||||
#define DLbus_Sensor_VOLUME_FLOW 0b011
|
||||
#define DLbus_Sensor_RAYS 0b110
|
||||
#define DLbus_Sensor_ROOM 0b111
|
||||
|
||||
// room sensor modes
|
||||
#define DLbus_RSM_AUTO 0b00
|
||||
#define DLbus_RSM_NORMAL 0b01
|
||||
#define DLbus_RSM_LOWER 0b10
|
||||
#define DLbus_RSM_STANDBY 0b11
|
||||
|
||||
boolean P092_fetch_sensor(int number, sP092_ReadData* ReadData);
|
||||
boolean P092_fetch_output(int number, sP092_ReadData* ReadData); // digital output byte(s)
|
||||
boolean P092_fetch_speed(int number, sP092_ReadData* ReadData); // speed byte(s)
|
||||
boolean P092_fetch_analog(int number, sP092_ReadData* ReadData); // analog byte(s)
|
||||
boolean P092_fetch_heatpower(int number, sP092_ReadData* ReadData); // heat power(s)
|
||||
boolean P092_fetch_heatmeter(int number, sP092_ReadData* ReadData); // heat meters(s)
|
||||
|
||||
// heat meter
|
||||
typedef struct {
|
||||
uint8_t IndexIsValid;
|
||||
int32_t power_index;
|
||||
int32_t kwh_index;
|
||||
int32_t mwh_index;
|
||||
} sDLbus_HMindex;
|
||||
sDLbus_HMindex P092_CheckHmRegister(int number);
|
||||
|
||||
/****************\
|
||||
DLBus P092_receiving
|
||||
\****************/
|
||||
|
||||
void Plugin_092_StartReceiving(void) {
|
||||
DLbus_Data->ISR_Receiving = false;
|
||||
DLbus_Data->DeviceBytes[0] = P092_DataSettings.DeviceByte0;
|
||||
DLbus_Data->DeviceBytes[1] = P092_DataSettings.DeviceByte1;
|
||||
DLbus_Data->ISR_PulseNumber = (((P092_DataSettings.DataBytes + DLbus_AdditionalRecBytes) * (DLbus_StartBits + 8 + DLbus_StopBits) + DLBus_SyncBits) * DLBus_BitChangeFactor) + DLBus_ReserveBytes;
|
||||
DLbus_Data->ISR_MinPulseWidth = P092_DataSettings.DLbus_MinPulseWidth;
|
||||
DLbus_Data->ISR_MaxPulseWidth = P092_DataSettings.DLbus_MaxPulseWidth;
|
||||
DLbus_Data->ISR_MinDoublePulseWidth = P092_DataSettings.DLbus_MinDoublePulseWidth;
|
||||
DLbus_Data->ISR_MaxDoublePulseWidth = P092_DataSettings.DLbus_MaxDoublePulseWidth;
|
||||
DLbus_Data->StartReceiving();
|
||||
uint32_t start=millis();
|
||||
addLog(LOG_LEVEL_INFO, F("P092_receiving ..."));
|
||||
while ((timePassedSince(start)<100) && (DLbus_Data->ISR_PulseCount == 0)) {
|
||||
// wait for first pulse received (timeout 100ms)
|
||||
yield();
|
||||
}
|
||||
if (DLbus_Data->ISR_PulseCount == 0) {
|
||||
// nothing received
|
||||
DLbus_Data->ISR_Receiving = false;
|
||||
addLog(LOG_LEVEL_ERROR, F("## StartReceiving: Error: Nothing received! No DL bus connected!"));
|
||||
}
|
||||
}
|
||||
|
||||
/****************\
|
||||
DLBus get data
|
||||
\****************/
|
||||
|
||||
boolean P092_GetData(int OptionIdx, int CurIdx, sP092_ReadData* ReadData) {
|
||||
String log;
|
||||
boolean result = false;
|
||||
switch (OptionIdx) {
|
||||
case 1: //F("Sensor")
|
||||
log = F("Get Sensor");
|
||||
log += CurIdx;
|
||||
if (CurIdx > P092_DataSettings.MaxSensors) {
|
||||
result=false;
|
||||
break;
|
||||
}
|
||||
ReadData->Idx = P092_DataSettings.IdxSensor;
|
||||
result = P092_fetch_sensor(CurIdx, ReadData);
|
||||
break;
|
||||
case 2: //F("Sensor")
|
||||
log = F("Get ExtSensor");
|
||||
log += CurIdx;
|
||||
if (CurIdx > P092_DataSettings.MaxExtSensors) {
|
||||
result=false;
|
||||
break;
|
||||
}
|
||||
ReadData->Idx = P092_DataSettings.IdxExtSensor;
|
||||
result = P092_fetch_sensor(CurIdx, ReadData);
|
||||
break;
|
||||
case 3: //F("Digital output")
|
||||
log = F("Get DigitalOutput");
|
||||
log += CurIdx;
|
||||
if (CurIdx > (8 * P092_DataSettings.OutputBytes)) {
|
||||
result=false;
|
||||
break;
|
||||
}
|
||||
result = P092_fetch_output(CurIdx, ReadData);
|
||||
break;
|
||||
case 4: //F("Speed step")
|
||||
log = F("Get SpeedStep");
|
||||
log += CurIdx;
|
||||
if (CurIdx > P092_DataSettings.SpeedBytes) {
|
||||
result=false;
|
||||
break;
|
||||
}
|
||||
result = P092_fetch_speed(CurIdx, ReadData);
|
||||
break;
|
||||
case 5: //F("Analog output")
|
||||
log = F("Get AnalogOutput");
|
||||
log += CurIdx;
|
||||
if (CurIdx > P092_DataSettings.AnalogBytes) {
|
||||
result=false;
|
||||
break;
|
||||
}
|
||||
result = P092_fetch_analog(CurIdx, ReadData);
|
||||
break;
|
||||
case 6: //F("Heat power (kW)")
|
||||
log = F("Get HeatPower");
|
||||
log += CurIdx;
|
||||
if (CurIdx > P092_DataSettings.MaxHeatMeters) {
|
||||
result=false;
|
||||
break;
|
||||
}
|
||||
result = P092_fetch_heatpower(CurIdx, ReadData);
|
||||
break;
|
||||
case 7: //F("Heat meter (MWh)"
|
||||
log = F("Get HeatMeter");
|
||||
log += CurIdx;
|
||||
if (CurIdx > P092_DataSettings.MaxHeatMeters) {
|
||||
result=false;
|
||||
break;
|
||||
}
|
||||
result = P092_fetch_heatmeter(CurIdx, ReadData);
|
||||
break;
|
||||
}
|
||||
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
|
||||
log += F(": ");
|
||||
if (result) {
|
||||
log += String(ReadData->value, 1);
|
||||
}
|
||||
else {
|
||||
log += F("nan");
|
||||
}
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
boolean P092_fetch_sensor(int number, sP092_ReadData* ReadData) {
|
||||
float value;
|
||||
ReadData->mode = -1;
|
||||
number = ReadData->Idx + (number - 1) * 2;
|
||||
int32_t sensorvalue = (DLbus_Data->ByteStream[number + 1] << 8) | DLbus_Data->ByteStream[number];
|
||||
if (sensorvalue == 0) {
|
||||
return false;
|
||||
}
|
||||
uint8_t sensortype = (sensorvalue & 0x7000) >> 12;
|
||||
if (!(sensorvalue & 0x8000)) { // sign positive
|
||||
sensorvalue &= 0xfff;
|
||||
// calculations for different sensor types
|
||||
switch (sensortype) {
|
||||
case DLbus_Sensor_DIGITAL:
|
||||
value = false;
|
||||
break;
|
||||
case DLbus_Sensor_TEMP:
|
||||
value = sensorvalue * 0.1;
|
||||
break;
|
||||
case DLbus_Sensor_RAYS:
|
||||
value = sensorvalue;
|
||||
break;
|
||||
case DLbus_Sensor_VOLUME_FLOW:
|
||||
value = sensorvalue * 4;
|
||||
break;
|
||||
case DLbus_Sensor_ROOM:
|
||||
ReadData->mode = (sensorvalue & 0x600) >> 9;
|
||||
value = (sensorvalue & 0x1ff) * 0.1;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else { // sign negative
|
||||
sensorvalue |= 0xf000;
|
||||
// calculations for different sensor types
|
||||
switch (sensortype) {
|
||||
case DLbus_Sensor_DIGITAL:
|
||||
value = true;
|
||||
break;
|
||||
case DLbus_Sensor_TEMP:
|
||||
value = (sensorvalue - 0x10000) * 0.1;
|
||||
break;
|
||||
case DLbus_Sensor_RAYS:
|
||||
value = sensorvalue - 0x10000;
|
||||
break;
|
||||
case DLbus_Sensor_VOLUME_FLOW:
|
||||
value = (sensorvalue - 0x10000) * 4;
|
||||
break;
|
||||
case DLbus_Sensor_ROOM:
|
||||
ReadData->mode = (sensorvalue & 0x600) >> 9;
|
||||
value = ((sensorvalue & 0x1ff) - 0x10000) * 0.1;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
ReadData->value = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean P092_fetch_output(int number, sP092_ReadData* ReadData) {
|
||||
int32_t outputs;
|
||||
|
||||
if (P092_DataSettings.OutputBytes > 1)
|
||||
outputs = (DLbus_Data->ByteStream[P092_DataSettings.IdxOutput + 1] << 8) | DLbus_Data->ByteStream[P092_DataSettings.IdxOutput];
|
||||
else
|
||||
outputs = DLbus_Data->ByteStream[P092_DataSettings.IdxOutput];
|
||||
if (outputs & (1 << (number - 1)))
|
||||
ReadData->value = 1;
|
||||
else
|
||||
ReadData->value = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean P092_fetch_speed(int number, sP092_ReadData* ReadData) {
|
||||
uint8_t speedbyte;
|
||||
|
||||
if ((P092_DataSettings.IdxDrehzahl + (number - 1)) >= P092_DataSettings.IdxAnalog) {
|
||||
// wrong index for speed, overlapping next index (IdxAnalog)
|
||||
return false;
|
||||
}
|
||||
speedbyte = DLbus_Data->ByteStream[P092_DataSettings.IdxDrehzahl + (number - 1)];
|
||||
if (speedbyte & 0x80)
|
||||
return false;
|
||||
ReadData->value = (speedbyte & 0x1f);
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean P092_fetch_analog(int number, sP092_ReadData* ReadData) {
|
||||
uint8_t analogbyte;
|
||||
|
||||
if ((P092_DataSettings.IdxAnalog + (number - 1)) >= P092_DataSettings.IdxHmRegister) {
|
||||
// wrong index for analog, overlapping next index (IdxHmRegister)
|
||||
return false;
|
||||
}
|
||||
analogbyte = DLbus_Data->ByteStream[P092_DataSettings.IdxAnalog + (number - 1)];
|
||||
if (analogbyte & 0x80)
|
||||
return false;
|
||||
ReadData->value = (analogbyte * 0.1);
|
||||
return true;
|
||||
}
|
||||
|
||||
sDLbus_HMindex P092_CheckHmRegister(int number) {
|
||||
sDLbus_HMindex result;
|
||||
|
||||
result.IndexIsValid = 0;
|
||||
switch (number) {
|
||||
case 1:
|
||||
if ((DLbus_Data->ByteStream[P092_DataSettings.IdxHmRegister] & 0x1) == 0)
|
||||
return result;
|
||||
result.power_index = P092_DataSettings.IdxHeatMeter1;
|
||||
result.kwh_index = P092_DataSettings.IdxkWh1;
|
||||
result.mwh_index = P092_DataSettings.IdxMWh1;
|
||||
break;
|
||||
case 2:
|
||||
if ((DLbus_Data->ByteStream[P092_DataSettings.IdxHmRegister] & 0x2) == 0)
|
||||
return result;
|
||||
result.power_index = P092_DataSettings.IdxHeatMeter2;
|
||||
result.kwh_index = P092_DataSettings.IdxkWh2;
|
||||
result.mwh_index = P092_DataSettings.IdxMWh2;
|
||||
break;
|
||||
case 3:
|
||||
if ((DLbus_Data->ByteStream[P092_DataSettings.IdxHmRegister] & 0x4) == 0)
|
||||
return result;
|
||||
result.power_index = P092_DataSettings.IdxHeatMeter3;
|
||||
result.kwh_index = P092_DataSettings.IdxkWh3;
|
||||
result.mwh_index = P092_DataSettings.IdxMWh3;
|
||||
break;
|
||||
default:
|
||||
return result;
|
||||
}
|
||||
result.IndexIsValid = 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
boolean P092_fetch_heatpower(int number, sP092_ReadData* ReadData) {
|
||||
// current power
|
||||
int32_t high;
|
||||
sDLbus_HMindex HMindex = P092_CheckHmRegister(number);
|
||||
if (HMindex.IndexIsValid == 0)
|
||||
return false;
|
||||
uint8_t b1 = DLbus_Data->ByteStream[HMindex.power_index];
|
||||
uint8_t b2 = DLbus_Data->ByteStream[HMindex.power_index + 1];
|
||||
if (P092_DataSettings.CurrentHmBytes > 2) {
|
||||
uint8_t b3 = DLbus_Data->ByteStream[HMindex.power_index + 2];
|
||||
uint8_t b4 = DLbus_Data->ByteStream[HMindex.power_index + 3];
|
||||
high = 0x10000 * b4 + 0x100 * b3 + b2;
|
||||
int low = (b1 * 10) / 0x100;
|
||||
if (!(b4 & 0x80)) // sign positive
|
||||
ReadData->value = (10 * high + low) / 100;
|
||||
else // sign negative
|
||||
ReadData->value = (10 * (high - 0x10000) - low) / 100;
|
||||
}
|
||||
else {
|
||||
high = (b2 << 8) | b1;
|
||||
if ((b2 & 0x80) == 0) // sign positive
|
||||
ReadData->value = high / 10;
|
||||
else // sign negative
|
||||
ReadData->value = (high - 0x10000) / 10;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean P092_fetch_heatmeter(int number, sP092_ReadData* ReadData) {
|
||||
// heat meter
|
||||
int32_t heat_meter;
|
||||
float heat_meter_mwh;
|
||||
|
||||
sDLbus_HMindex HMindex = P092_CheckHmRegister(number);
|
||||
if (HMindex.IndexIsValid == 0)
|
||||
return false;
|
||||
heat_meter = (DLbus_Data->ByteStream[HMindex.kwh_index + 1] << 8) | DLbus_Data->ByteStream[HMindex.kwh_index];
|
||||
heat_meter_mwh = (heat_meter * 0.1) / 1000; // in MWh
|
||||
if (heat_meter_mwh > 1.0) {
|
||||
// in kWh
|
||||
heat_meter = heat_meter_mwh;
|
||||
heat_meter_mwh -= heat_meter;
|
||||
}
|
||||
// MWh
|
||||
heat_meter = (DLbus_Data->ByteStream[HMindex.mwh_index + 1] << 8) | DLbus_Data->ByteStream[HMindex.mwh_index];
|
||||
ReadData->value = heat_meter_mwh + heat_meter;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // USES_P092
|
||||
@@ -723,6 +723,7 @@ To create/register a plugin, you have to :
|
||||
#define USES_P063 // TTP229_KeyPad
|
||||
#define USES_P073 // 7DG
|
||||
#define USES_P079 // Wemos Motoshield
|
||||
#define USES_P092 // DL-Bus
|
||||
#endif
|
||||
|
||||
|
||||
|
||||