From 00d569b7a966a74a29c1ef81818a80c3fb510aa3 Mon Sep 17 00:00:00 2001 From: Bert Melis Date: Fri, 4 Oct 2024 08:52:41 +0200 Subject: [PATCH 1/2] cleanup --- README.md | 60 ++++++++++++++++++++++++++----------------------- src/GWG/GWG.cpp | 2 +- src/VS1/VS1.cpp | 5 +++-- src/VS2/VS2.cpp | 22 +++++++++--------- src/VS2/VS2.h | 2 +- 5 files changed, 48 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 000133c..0deef86 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # VitoWiFi -Library for ESP8266 to communicate with Viessmann systems using a (DIY) serial optolink. +Library for ESP32, ESP8266 and Linux to communicate with Viessmann systems using a (DIY) serial optolink. Based on the fantastic work on [openv](https://github.com/openv/openv/wiki). @@ -10,7 +10,7 @@ Based on the fantastic work on [openv](https://github.com/openv/openv/wiki). ## Features -- VS1 (KW) and VS2 (P300) support. Older systems using the GWG protocol are not supported +- VS1 (KW) and VS2 (P300) support. The older GWG protocol is also supported. - Non-blocking API calls - For the Arduino framework and POSIX systems (Linux, tested on a Raspberry Pi 1B) - Possible to use `SoftwareSerial` on ESP8266 @@ -32,7 +32,7 @@ Based on the fantastic work on [openv](https://github.com/openv/openv/wiki). ## Hardware -The optolink hardware for ESP8266 and ESP32 is simple. Using the circuit below you can build your own optolink. +The optolink hardware can be really simple. Using the circuit below you can build your own optolink. Please also check the [openv wiki, in German](https://github.com/openv/openv/wiki/Die-Optolink-Schnittstelle) for more implementations. ``` @@ -75,7 +75,7 @@ The canonical way to use this library is simple and straightforward. A few steps - attach the callbacks - start VitoWiFi 5. in `void loop()`: - - call `loop()` regularly. It keeps VitoWiFi running. + - call `loop()` regularly. It keeps VitoWiFi running. Ideally it is called more than once every 10ms. A simple program for ESP32 to test and query your devicetype looks like this: @@ -160,11 +160,11 @@ if (currentIndex > 0) { ### More examples -you can find more examples in the `examples` directory in this repo. +You can find more examples in the `examples` directory in this repo. ## Datapoints -When defining your datapoints, you need to specify the name, address, length and converion type. Datapoints in C++ looks like this: +When defining your datapoints, you need to specify the name, address, length and conversion type. Datapoints in C++ looks like this: ```cpp VitoWiFi::Datapoint datapoint1("outside temp", 0x5525, 2, VitoWiFi::div10); @@ -178,24 +178,26 @@ While name, address and length are self-explanatory, conversion type is a bit mo ### Conversion types -Data is stored in binary and often needs a conversion function to transform into a more readable type. This is specified by the conversion type, the last argument in the datapoint definition. +Data is stored in binary and often needs a conversion function to transform into a more usable type. This is specified by the conversion type, the last argument in the datapoint definition. -Since C++ is a strongly typed programming language so using the right type is important (read: mandatory). Each conversion type corresponds with a certain type. Reading or writing has to be done using this specific type and failure to do so will not work or will lead to undefined results. +C++ is a strongly typed programming language so using the right type is important (read: mandatory). Each conversion type corresponds to a certain type. Reading or writing has to be done using this specific type and failure to do so will not work or will lead to undefined results. In the table below you can find how to define your datapoints: |name|size|converter|return type|remarks| |---|---|---|---|---| |Temperature|2|div10|float|| -|Temperature short|1|noconv|uint8_t|equivalent to Mode| -|Power|1|div2|float|also used for temperature in GWG| -|Status|1|noconv|bool|this is the same as 'Temperature short' and 'Mode'. The `uint8_t` value will be implicitely converted to bool.| -|Hours|4|div3600|float|this is in fact a `Count` datapoint (seconds) converted to hours.| +|Temperature short|1|noconv|uint8_t|Equivalent to Mode| +|Power|1|div2|float|Also used for temperature in GWG| +|Status|1|noconv|bool|This is the same as 'Temperature short' and 'Mode'. The `uint8_t` value will be implicitely converted to bool.| +|Hours|4|div3600|float|This is in fact a `Count` datapoint (seconds) converted to hours.| |Count|4|noconv|uint32_t|| |Count short|2|noconv|uint16_t|| -|Mode|1|noconv|uint8_t|possibly castable to ENUM| +|Mode|1|noconv|uint8_t|Possibly castable to ENUM| |CoP|1|div10|float|Also used for heating curve slope| +Mind that the converters are declared within the `VitoWiFi` namespace. + ## Bugs and feature requests Please use Github's facilities to get in touch. While the issue template is not mandatory to use, please use it at least as a starting point to supply the needed info for bughunting. @@ -204,9 +206,9 @@ Please use Github's facilities to get in touch. While the issue template is not Below is an overview of all commonly used methods. For extra functions you can consult the source code. -### Datapoint +### `VitoWiFi::Datapoint` -##### `Datapoint(const char* name, uint16_t address, uint8_t length, const Converter& converter)` +##### `VitoWiFi::Datapoint(const char* name, uint16_t address, uint8_t length, const Converter& converter)` Constructor for datapoints. @@ -227,16 +229,16 @@ Returns `VariantValue` which is implicitely castable to the correct datatype. Co ##### `VariantValue decode(const uint8_t* data, uint8_t length) const` -Decodes the data in the supplied `data`-buffer using the converter class attached. +Decodes the data in the supplied `data`-buffer using the Converter class attached. Returns `VariantValue` which is implicitely castable to the correct datatype. Consult the table above. ##### `void encode(uint8_t* buf, uint8_t len, const VariantValue& value) const` -Encodes `value` into the supplied `buf` with maximum size `len`. The size should obviously be at least the length of the datapoint. +Encodes `value` into the supplied `buf` with maximum size `len`. The size must be at least the length of the datapoint. `VariantValue` is a type to implicitely convert datatypes for use in VitoWiFi. Make sure to use the type that matches your Converter type. -### `PacketVS2` +### `VitoWiFi::PacketVS2` Only used in VS2. This type is used in the onResponse callback and contains the returned data. Most users will only use the following two methods and only if they want to access the raw data. Otherwise, the data can be decoded using the corresponding `Datapoint`. @@ -249,25 +251,27 @@ Returns the number of bytes in the payload. Returns a pointer to the payload. -### VitoWiFi +### `VitoWiFi::VitoWiFi` -##### `VitoWiFi(IFACE* interface)` +##### `VitoWiFi::VitoWiFi(IFACE* interface)` -Constructor of the VitoWiFi class. `PROTOCOL_VERSION` can be `GWG`, `VS1` or `VS2`. If your Viessmann device is somewhat modern, you should use `VS2`. +Constructor of the VitoWiFi class. `PROTOCOL_VERSION` can be `VitoWiFi::GWG`, `VitoWiFi::VS1` or `VitoWiFi::VS2`. If your Viessmann device is somewhat modern, you should use `VitoWiFi::VS2`. `interface` can be any of the `HardwareSerial` interfaces (`Serial`, `Serial1`...) on Arduino boards, `SoftwareSerial` (on ESP8266) or if you are on Linux, pass the c-string depicting your device (for example `"/dev/ttyUSB0"`). ##### `void onResponse(typename PROTOCOLVERSION::OnResponseCallback callback)` -Attach an onResponse callback. You can only attack one and will overwrite the previously attached callback. +Attach an onResponse callback. You can only attach one and will overwrite the previously attached callback. The callback has the following signature: -`VS1`: `void (const uint8_t*, uint8_t, const VitoWiFi::Datapoint&)` -`VS2`: `void (const VitoWiFi::PacketVS2&, const VitoWiFi::Datapoint&)` + +- `VitoWiFi::VS1`: `void (const uint8_t*, uint8_t, const VitoWiFi::Datapoint&)` +- `VitoWiFi::VS2`: `void (const VitoWiFi::PacketVS2&, const VitoWiFi::Datapoint&)` ##### `void onError(typename PROTOCOLVERSION::OnErrorCallback callback)` Attach an onError callback. You can only attack one and will overwrite the previously attached callback. The callback has the following signature: -`void (VitoWiFi::OptolinkResult, const VitoWiFi::Datapoint&)` + +- `void (VitoWiFi::OptolinkResult, const VitoWiFi::Datapoint&)` ##### `bool begin()` @@ -287,7 +291,7 @@ Read `datapoint`. Returns `true` on success. ##### `bool write(Datapoint datapoint, T value)` -Write `value` with type `T` to `datapoint`. Make sure to use the correct type. consult the table with types in the "Datapoints" section. +Write `value` with type `T` to `datapoint`. Make sure to use the correct type. Consult the table with types in the "Datapoints" section. ##### `write(Datapoint datapoint, const uint8_t* data, uint8_t length)` @@ -308,11 +312,11 @@ Used in the onError callback. Possible returned values are: ##### `VW_START_PAYLOAD_LENGTH` -This macro sets the initial payload (data) length VitoWiFi allocates for incoming packets. If you know beforehand the maximum data length you are going to request, you can set this to that value to prevent reallocation of dynamic memory. The default is 10 bytes. +This macro sets the initial payload (data) length for incoming packets. VitoWiFi will increased the buffer if needed. If you know the maximum data length you are going to request beforehand, use this set to prevent dynamic memory reallocation. The default is 10 bytes. ## Bugs and feature requests -Please use Github's facilities, issues and discussions, to get in touch. +Please use Githubs facilities, issues and discussions, to get in touch. When creating a bug report, please use the provided template. In any case, better to include too much info than too little. ## License diff --git a/src/GWG/GWG.cpp b/src/GWG/GWG.cpp index 83e7041..8f871b0 100644 --- a/src/GWG/GWG.cpp +++ b/src/GWG/GWG.cpp @@ -199,6 +199,7 @@ void GWG::_setState(State state) { void GWG::_init() { if (_interface->available()) { if (_interface->read() == VitoWiFiInternals::ProtocolBytes.ENQ && _currentDatapoint) { + _bytesTransferred = 0; _setState(State::SEND); } } @@ -220,7 +221,6 @@ void GWG::_receive() { _lastMillis = _currentMillis; } if (_bytesTransferred == _currentRequest.length()) { - _bytesTransferred = 0; _setState(State::INIT); _tryOnResponse(); } diff --git a/src/VS1/VS1.cpp b/src/VS1/VS1.cpp index aaec45a..f3844a3 100644 --- a/src/VS1/VS1.cpp +++ b/src/VS1/VS1.cpp @@ -192,7 +192,6 @@ void VS1::loop() { } // double timeout to accomodate for connection initialization if (_currentDatapoint && _currentMillis - _requestTime > 4000UL) { - _bytesTransferred = 0; _setState(State::INIT); _tryOnError(OptolinkResult::TIMEOUT); } @@ -214,6 +213,7 @@ void VS1::_init() { if (_interface->available()) { if (_interface->read() == VitoWiFiInternals::ProtocolBytes.ENQ) { _lastMillis = _currentMillis; + _bytesTransferred = 0; _setState(State::SYNC_ENQ); } } else { @@ -229,6 +229,7 @@ void VS1::_init() { void VS1::_syncEnq() { if (_currentMillis - _lastMillis < 50) { if (_currentDatapoint && _interface->write(&VitoWiFiInternals::ProtocolBytes.ENQ_ACK, 1) == 1) { + _bytesTransferred = 0; _setState(State::SEND); _send(); // speed up things } @@ -242,6 +243,7 @@ void VS1::_syncEnq() { void VS1::_syncRecv() { if (_currentMillis - _lastMillis < 50) { if (_currentDatapoint) { + _bytesTransferred = 0; _setState(State::SEND); } } else { @@ -268,7 +270,6 @@ void VS1::_receive() { _lastMillis = _currentMillis; } if (_bytesTransferred == _currentDatapoint.length()) { - _bytesTransferred = 0; _setState(State::SYNC_RECV); _tryOnResponse(); } diff --git a/src/VS2/VS2.cpp b/src/VS2/VS2.cpp index 3069700..53adda2 100644 --- a/src/VS2/VS2.cpp +++ b/src/VS2/VS2.cpp @@ -16,7 +16,7 @@ VS2::VS2(HardwareSerial* interface) , _currentMillis(vw_millis()) , _lastMillis(_currentMillis) , _requestTime(0) -, _bytesSent(0) +, _bytesTransferred(0) , _interface(nullptr) , _parser() , _currentDatapoint(Datapoint(nullptr, 0, 0, noconv)) @@ -37,7 +37,7 @@ VS2::VS2(SoftwareSerial* interface) , _currentMillis(vw_millis()) , _lastMillis(_currentMillis) , _requestTime(0) -, _bytesSent(0) +, _bytesTransferred(0) , _interface(nullptr) , _parser() , _currentDatapoint(Datapoint(nullptr, 0, 0, noconv)) @@ -59,7 +59,7 @@ VS2::VS2(const char* interface) , _currentMillis(vw_millis()) , _lastMillis(_currentMillis) , _requestTime(0) -, _bytesSent(0) +, _bytesTransferred(0) , _interface(nullptr) , _parser() , _currentDatapoint(Datapoint(nullptr, 0, 0, noconv)) @@ -182,7 +182,7 @@ void VS2::loop() { // begin() not yet called break; } - if (_currentDatapoint && _currentMillis - _requestTime > 5000UL) { + if (_currentDatapoint && _currentMillis - _requestTime > 4000UL) { _setState(State::RESET); _tryOnError(OptolinkResult::TIMEOUT); } @@ -222,10 +222,10 @@ void VS2::_resetAck() { } void VS2::_init() { - _bytesSent += _interface->write(&VitoWiFiInternals::ProtocolBytes.SYNC[_bytesSent], - sizeof(VitoWiFiInternals::ProtocolBytes.SYNC) - _bytesSent); - if (_bytesSent == sizeof(VitoWiFiInternals::ProtocolBytes.SYNC)) { - _bytesSent = 0; + _bytesTransferred += _interface->write(&VitoWiFiInternals::ProtocolBytes.SYNC[_bytesTransferred], + sizeof(VitoWiFiInternals::ProtocolBytes.SYNC) - _bytesTransferred); + if (_bytesTransferred == sizeof(VitoWiFiInternals::ProtocolBytes.SYNC)) { + _bytesTransferred = 0; _lastMillis = _currentMillis; _setState(State::INIT_ACK); } @@ -263,9 +263,9 @@ void VS2::_sendStart() { } void VS2::_sendPacket() { - _bytesSent += _interface->write(&_currentPacket[_bytesSent], _currentPacket.length() - _bytesSent); - if (_bytesSent == _currentPacket.length()) { - _bytesSent = 0; + _bytesTransferred += _interface->write(&_currentPacket[_bytesTransferred], _currentPacket.length() - _bytesTransferred); + if (_bytesTransferred == _currentPacket.length()) { + _bytesTransferred = 0; _lastMillis = _currentMillis; _setState(State::SEND_CRC); } diff --git a/src/VS2/VS2.h b/src/VS2/VS2.h index 4abff4a..5089584 100644 --- a/src/VS2/VS2.h +++ b/src/VS2/VS2.h @@ -74,7 +74,7 @@ class VS2 { uint32_t _currentMillis; uint32_t _lastMillis; uint32_t _requestTime; - uint8_t _bytesSent; + uint8_t _bytesTransferred; VitoWiFiInternals::SerialInterface* _interface; VitoWiFiInternals::ParserVS2 _parser; Datapoint _currentDatapoint; From 7cd97a0a69bceecc69817fb3cd1733c1d75e2d30 Mon Sep 17 00:00:00 2001 From: Bert Melis Date: Tue, 7 Jan 2025 09:57:30 +0100 Subject: [PATCH 2/2] fix include --- src/Datapoint/Converter.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Datapoint/Converter.h b/src/Datapoint/Converter.h index b60f7a8..c83e884 100644 --- a/src/Datapoint/Converter.h +++ b/src/Datapoint/Converter.h @@ -9,6 +9,7 @@ the LICENSE file. #pragma once #include +#include #include #include