mirror of https://github.com/lumapu/ahoy.git
				
				
			
				 42 changed files with 1937 additions and 1595 deletions
			
			
		| After Width: | Height: | Size: 650 KiB | 
| After Width: | Height: | Size: 66 KiB | 
| @ -0,0 +1,47 @@ | |||
| # Prometheus Endpoint | |||
| Metrics available for AhoyDTU device, inverters and channels. | |||
| 
 | |||
| Prometheus metrics provided at `/metrics`.  | |||
| 
 | |||
| ## Labels | |||
| | Label name | Description                           |  | |||
| |:-----------|:--------------------------------------| | |||
| | version    | current installed version of AhoyDTU  | | |||
| | image      | currently not used                    | | |||
| | devicename | Device name from setup                | | |||
| | name       | Inverter name from setup              | | |||
| | serial     | Serial number of inverter             | | |||
| | enabled    | Communication enable for inverter     | | |||
| | inverter   | Inverter name from setup              | | |||
| | channel    | Channel name from setup               | | |||
| 
 | |||
| 
 | |||
| ## Exported Metrics | |||
| | Metric name                            | Type    | Description                                            | Labels       |  | |||
| |----------------------------------------|---------|--------------------------------------------------------|--------------| | |||
| | `ahoy_solar_info`                      | Gauge   | Information about the AhoyDTU device                   | version, image, devicename | | |||
| | `ahoy_solar_inverter_info`             | Gauge   | Information about the configured inverter(s)           | name, serial, enabled | | |||
| | `ahoy_solar_U_AC_volt`                 | Gauge   | AC voltage of inverter [V]                             | inverter  |  | |||
| | `ahoy_solar_I_AC_ampere`               | Gauge   | AC current of inverter [A]                             | inverter  |  | |||
| | `ahoy_solar_P_AC_watt`                 | Gauge   | AC power of inverter [W]                               | inverter  |  | |||
| | `ahoy_solar_Q_AC_var`                  | Gauge   | AC reactive power[var]                                 | inverter  |  | |||
| | `ahoy_solar_F_AC_hertz`                | Gauge   | AC frequency [Hz]                                      | inverter  |  | |||
| | `ahoy_solar_PF_AC`                     | Gauge   | AC Power factor                                        | inverter  |  | |||
| | `ahoy_solar_Temp_celsius`              | Gauge   | Temperature of inverter                                | inverter  |  | |||
| | `ahoy_solar_ALARM_MES_ID`              | Gauge   | Last alarm message id of inverter                      | inverter  |  | |||
| | `ahoy_solar_YieldDay_wattHours`        | Counter | Energy converted to AC per day [Wh]                    | inverter  |  | |||
| | `ahoy_solar_YieldTotal_kilowattHours`  | Counter | Energy converted to AC since reset [kWh]               | inverter  |  | |||
| | `ahoy_solar_P_DC_watt`                 | Gauge   | DC power of inverter [W]                               | inverter  |  | |||
| | `ahoy_solar_Efficiency_ratio`          | Gauge   | ration AC Power over DC Power [%]                      | inverter  |  | |||
| | `ahoy_solar_U_DC_volt`                 | Gauge   | DC voltage of channel [V]                              | inverter, channel |  | |||
| | `ahoy_solar_I_DC_ampere`               | Gauge   | DC current of channel [A]                              | inverter, channel |  | |||
| | `ahoy_solar_P_DC_watt`                 | Gauge   | DC power of channel [P]                                | inverter, channel |  | |||
| | `ahoy_solar_YieldDay_wattHours`        | Counter | Energy converted to AC per day [Wh]                    | inverter, channel |  | |||
| | `ahoy_solar_YieldTotal_kilowattHours`  | Counter | Energy converted to AC since reset [kWh]               | inverter, channel |  | |||
| | `ahoy_solar_Irradiation_ratio`         | Gauge   | ratio DC Power over set maximum power per channel [%]  | inverter, channel | | |||
| | `ahoy_solar_radio_rx_success`          | Gauge   | NRF24 statistic                                        | | | |||
| | `ahoy_solar_radio_rx_fail`             | Gauge   | NRF24 statistic                                        | | | |||
| | `ahoy_solar_radio_rx_fail_answer`      | Gauge   | NRF24 statistic                                        | | | |||
| | `ahoy_solar_radio_frame_cnt`           | Gauge   | NRF24 statistic                                        | | | |||
| | `ahoy_solar_radio_tx_cnt`              | Gauge   | NRF24 statistic                                        | | | |||
| 
 | |||
| @ -1,36 +1,84 @@ | |||
| # Changelog v0.5.66 | |||
| 
 | |||
| **Note:** Version `0.5.42` to `0.5.65` were development versions. Last release version was `0.5.41` | |||
| Detailed change log (development changes): https://github.com/lumapu/ahoy/blob/945a671d27d10d0f7c175ebbf2fbb2806f9cd79a/src/CHANGES.md | |||
| 
 | |||
| 
 | |||
| * updated REST API and MQTT (both of them use the same functionality) | |||
| * improved stability | |||
| * Regular expressions for input fields which are used for MQTT to be compliant to MQTT | |||
| * WiFi optimization (AP Mode and STA in parallel, reconnect if local STA is unavailable) | |||
| * improved display of `/system` | |||
| * fix Update button protection (prevent double click #527) | |||
| * optimized scheduler #515 | |||
| * fix of duplicates in API `/api/record/live` (#526) | |||
| * added update information to `index.html` (check for update with github.com) | |||
| * fix web logout (auto logout) | |||
| * switched MQTT library | |||
| * removed MQTT `available_text` (can be deducted from `available`) | |||
| * enhanced MQTT documentation in `User_Manual.md` | |||
| * changed MQTT topic `status` to nummeric value, check documentation in `User_Manual.md` | |||
| * added immediate (each minute) report of inverter status MQTT #522 | |||
| * increased MQTT user, pwd and topic length to 64 characters + `\0`. (The string end `\0` reduces the available size by one) #516 | |||
| * added disable night communication flag to MQTT #505 | |||
| * added MQTT <TOPIC>/status to show status over all inverters | |||
| * added MQTT RX counter to index.html | |||
| * added protection mask to select which pages should be protected | |||
| * added monochrome display that show values also if nothing changed and in offline mode #498 | |||
| * added icons to index.html, added WiFi-strength symbol on each page | |||
| * refactored communication offset (adjustable in minutes now) | |||
| * factory reset formats entire little fs | |||
| * renamed sunrise / sunset on index.html to start / stop communication | |||
| * fixed static IP save | |||
| * fix NTP with static IP | |||
| * all values are displayed on /live even if they are 0 | |||
| * added NRF24 info to Systeminfo | |||
| * reordered enqueue commands after boot up to prevent same payload length for successive commands | |||
| # Changelog | |||
| 
 | |||
| (starting from release version `0.5.66`) | |||
| 
 | |||
| ## 0.5.78 | |||
| * further improvements regarding wifi #611, fix connection if only one AP with same SSID is there | |||
| * fix endless loop in `zerovalues` #564 | |||
| * fix auto discover again #565 | |||
| * added total values to autodiscover #630 | |||
| * improved zero at midnight #625 | |||
| 
 | |||
| ## 0.5.77 | |||
| * fix wrong filename for automatically created manifest (online installer) #620 | |||
| * added rotate display feature #619 | |||
| * improved Prometheus endpoint #615, thx to @fsck-block | |||
| * improved wifi to connect always to strongest RSSI, thx to @beegee3 #611 | |||
| 
 | |||
| ## 0.5.76 | |||
| * reduce MQTT retry interval from maximum speed to one second | |||
| * fixed homeassistant autodiscovery #565 | |||
| * implemented `getNTPTime` improvements #609 partially #611 | |||
| * added alarm messages to MQTT #177, #600, #608 | |||
| 
 | |||
| ## 0.5.75 | |||
| * fix wakeup issue, once wifi was lost during night the communication didn't start in the morning | |||
| * reenabled FlashStringHelper because of lacking RAM | |||
| * complete rewrite of monochrome display class, thx to @dAjaY85 -> displays are now configurable in setup | |||
| * fix power limit not possible #607 | |||
| 
 | |||
| ## 0.5.74 | |||
| * improved payload handling (retransmit all fragments on CRC error) | |||
| * improved `isAvailable`, checkes all record structs, inverter becomes available more early because version is check first | |||
| * fix tickers were not set if NTP is not available | |||
| * disabled annoying `FlashStringHelper` it gives randomly Expeptions during development, feels more stable since then | |||
| * moved erase button to the bottom in settings, not nice but more functional | |||
| * split `tx_count` to `tx_cnt` and `retransmits` in `system.html` | |||
| * fix mqtt retransmit IP address #602 | |||
| * added debug infos for `scheduler` (web -> `/debug` as trigger prints list of tickers to serial console) | |||
| 
 | |||
| ## 0.5.73 | |||
| * improved payload handling (request / retransmit) #464 | |||
| * included alarm ID parse to serial console (in development) | |||
| 
 | |||
| ## 0.5.72 | |||
| * repaired system, scheduler was not called any more #596 | |||
| 
 | |||
| ## 0.5.71 | |||
| * improved wifi handling and tickers, many thanks to @beegee3 #571 | |||
| * fixed YieldTotal correction calculation #589 | |||
| * fixed serial output of power limit acknowledge #569 | |||
| * reviewed `sendDiscoveryConfig` #565 | |||
| * merged PR `Monodisplay`, many thanks to @dAjaY85 #566, Note: (settings are introduced but not able to be modified, will be included in next version) | |||
| 
 | |||
| ## 0.5.70 | |||
| * corrected MQTT `comm_disabled` #529 | |||
| * fix Prometheus and JSON endpoints (`config_override.h`) #561 | |||
| * publish MQTT with fixed interval even if inverter is not available #542 | |||
| * added JSON settings upload. NOTE: settings JSON download changed, so only settings should be uploaded starting from version `0.5.70` #551 | |||
| * MQTT topic and inverter name have more allowed characters: `[A-Za-z0-9./#$%&=+_-]+`, thx: @Mo Demman | |||
| * improved potential issue with `checkTicker`, thx @cbscpe | |||
| * MQTT option for reset values on midnight / not avail / communication stop #539 | |||
| * small fix in `tickIVCommunication` #534 | |||
| * add `YieldTotal` correction, eg. to have the option to zero at year start #512 | |||
| 
 | |||
| ## 0.5.69 | |||
| * merged SH1106 1.3" Display, thx @dAjaY85 | |||
| * added SH1106 to automatic build | |||
| * added IP address to MQTT (version, device and IP are retained and only transmitted once after boot) #556 | |||
| * added `set_power_limit` acknowledge MQTT publish #553 | |||
| * changed: version, device name are only published via MQTT once after boot | |||
| * added `Login` to menu if admin password is set #554 | |||
| * added `development` to second changelog link in `index.html` #543 | |||
| * added interval for MQTT (as option). With this settings MQTT live data is published in a fixed timing (only if inverter is available) #542, #523 | |||
| * added MQTT `comm_disabled` #529 | |||
| * changed name of binaries, moved GIT-Sha to the front #538 | |||
| 
 | |||
| ## 0.5.68 | |||
| * repaired receive payload | |||
| * Powerlimit is transfered immediately to inverter | |||
| 
 | |||
| ## 0.5.67 | |||
| * changed calculation of start / stop communication to 1 min after last comm. stop #515 | |||
| * moved payload send to `payload.h`, function `ivSend` #515 | |||
| * payload: if last frame is missing, request all frames again | |||
|  | |||
| @ -1,161 +0,0 @@ | |||
| /*
 | |||
|     CircularBuffer - An Arduino circular buffering library for arbitrary types. | |||
| 
 | |||
|     Created by Ivo Pullens, Emmission, 2014 -- www.emmission.nl | |||
| 
 | |||
|     This library is free software; you can redistribute it and/or | |||
|     modify it under the terms of the GNU Lesser General Public | |||
|     License as published by the Free Software Foundation; either | |||
|     version 2.1 of the License, or (at your option) any later version. | |||
| 
 | |||
|     This library is distributed in the hope that it will be useful, | |||
|     but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | |||
|     Lesser General Public License for more details. | |||
| 
 | |||
|     You should have received a copy of the GNU Lesser General Public | |||
|     License along with this library; if not, write to the Free Software | |||
|     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | |||
| */ | |||
| 
 | |||
| #ifndef CircularBuffer_h | |||
| #define CircularBuffer_h | |||
| 
 | |||
| #if defined(ESP8266) || defined(ESP32) | |||
| #define DISABLE_IRQ noInterrupts() | |||
| #define RESTORE_IRQ interrupts() | |||
| #else | |||
| #define DISABLE_IRQ       \ | |||
|     uint8_t sreg = SREG;    \ | |||
|     cli(); | |||
| 
 | |||
| #define RESTORE_IRQ        \ | |||
|     SREG = sreg; | |||
| #endif | |||
| 
 | |||
| template <class BUFFERTYPE, uint8_t BUFFERSIZE> | |||
| class CircularBuffer { | |||
| 
 | |||
|     typedef BUFFERTYPE BufferType; | |||
|     BufferType Buffer[BUFFERSIZE]; | |||
| 
 | |||
|     public: | |||
|         CircularBuffer() : m_buff(Buffer) { | |||
|             m_size = BUFFERSIZE; | |||
|             clear(); | |||
|         } | |||
| 
 | |||
|         /** Clear all entries in the circular buffer. */ | |||
|         void clear(void) | |||
|         { | |||
|             m_front = 0; | |||
|             m_fill  = 0; | |||
|         } | |||
| 
 | |||
|         /** Test if the circular buffer is empty */ | |||
|         inline bool empty(void) const | |||
|         { | |||
|             return !m_fill; | |||
|         } | |||
| 
 | |||
|         /** Return the number of records stored in the buffer */ | |||
|         inline uint8_t available(void) const | |||
|         { | |||
|             return m_fill; | |||
|         } | |||
| 
 | |||
|         /** Test if the circular buffer is full */ | |||
|         inline bool full(void) const | |||
|         { | |||
|             return m_fill == m_size; | |||
|         } | |||
| 
 | |||
|         inline uint8_t getFill(void) const { | |||
|             return m_fill; | |||
|         } | |||
| 
 | |||
|         /** Aquire record on front of the buffer, for writing.
 | |||
|          * After filling the record, it has to be pushed to actually | |||
|          * add it to the buffer. | |||
|          * @return Pointer to record, or NULL when buffer is full. | |||
|          */ | |||
|         BUFFERTYPE* getFront(void) const | |||
|         { | |||
|             DISABLE_IRQ; | |||
|             BUFFERTYPE* f = NULL; | |||
|             if (!full()) | |||
|                 f = get(m_front); | |||
|             RESTORE_IRQ; | |||
|             return f; | |||
|         } | |||
| 
 | |||
|         /** Push record to front of the buffer
 | |||
|          * @param record   Record to push. If record was aquired previously (using getFront) its | |||
|          *                 data will not be copied as it is already present in the buffer. | |||
|          * @return True, when record was pushed successfully. | |||
|          */ | |||
|         bool pushFront(BUFFERTYPE* record) | |||
|         { | |||
|             bool ok = false; | |||
|             DISABLE_IRQ; | |||
|             if (!full()) | |||
|             { | |||
|                 BUFFERTYPE* f = get(m_front); | |||
|                 if (f != record) | |||
|                     *f = *record; | |||
|                 m_front = (m_front+1) % m_size; | |||
|                 m_fill++; | |||
|                 ok = true; | |||
|             } | |||
|             RESTORE_IRQ; | |||
|             return ok; | |||
|         } | |||
| 
 | |||
|         /** Aquire record on back of the buffer, for reading.
 | |||
|          * After reading the record, it has to be pop'ed to actually | |||
|          * remove it from the buffer. | |||
|          * @return Pointer to record, or NULL when buffer is empty. | |||
|          */ | |||
|         BUFFERTYPE* getBack(void) const | |||
|         { | |||
|             BUFFERTYPE* b = NULL; | |||
|             DISABLE_IRQ; | |||
|             if (!empty()) | |||
|                 b = get(back()); | |||
|             RESTORE_IRQ; | |||
|             return b; | |||
|         } | |||
| 
 | |||
|         /** Remove record from back of the buffer.
 | |||
|          * @return True, when record was pop'ed successfully. | |||
|          */ | |||
|         bool popBack(void) | |||
|         { | |||
|             bool ok = false; | |||
|             DISABLE_IRQ; | |||
|             if (!empty()) | |||
|             { | |||
|                 m_fill--; | |||
|                 ok = true; | |||
|             } | |||
|             RESTORE_IRQ; | |||
|             return ok; | |||
|         } | |||
| 
 | |||
|     protected: | |||
|         inline BUFFERTYPE * get(const uint8_t idx) const | |||
|         { | |||
|             return &(m_buff[idx]); | |||
|         } | |||
|         inline uint8_t back(void) const | |||
|         { | |||
|             return (m_front - m_fill + m_size) % m_size; | |||
|         } | |||
| 
 | |||
|         uint8_t          m_size;     // Total number of records that can be stored in the buffer.
 | |||
|         BUFFERTYPE* const m_buff; | |||
|         volatile uint8_t m_front;    // Index of front element (not pushed yet).
 | |||
|         volatile uint8_t m_fill;     // Amount of records currently pushed.
 | |||
| }; | |||
| 
 | |||
| #endif // CircularBuffer_h
 | |||
| @ -1,27 +0,0 @@ | |||
| //-----------------------------------------------------------------------------
 | |||
| // 2022 Ahoy, https://ahoydtu.de
 | |||
| // Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
 | |||
| //-----------------------------------------------------------------------------
 | |||
| 
 | |||
| #ifndef __AHOY_TIMER_H__ | |||
| #define __AHOY_TIMER_H__ | |||
| 
 | |||
| #include <Arduino.h> | |||
| 
 | |||
| namespace ah { | |||
|     inline bool checkTicker(uint32_t *ticker, uint32_t interval) { | |||
|         uint32_t mil = millis(); | |||
|         if(mil >= *ticker) { | |||
|             *ticker = mil + interval; | |||
|             return true; | |||
|         } | |||
|         else if(mil < (*ticker - interval)) { | |||
|             *ticker = mil + interval; | |||
|             return true; | |||
|         } | |||
| 
 | |||
|         return false; | |||
|     } | |||
| } | |||
| 
 | |||
| #endif /*__AHOY_TIMER_H__*/ | |||
| @ -1,33 +0,0 @@ | |||
| //-----------------------------------------------------------------------------
 | |||
| // 2022 Ahoy, https://ahoydtu.de
 | |||
| // Lukas Pusch, lukas@lpusch.de
 | |||
| // Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
 | |||
| //-----------------------------------------------------------------------------
 | |||
| 
 | |||
| #ifndef __HANDLER_H__ | |||
| #define __HANDLER_H__ | |||
| 
 | |||
| #include <memory> | |||
| #include <functional> | |||
| #include <list> | |||
| 
 | |||
| template<class TYPE> | |||
| class Handler { | |||
|     public: | |||
|         Handler() {} | |||
| 
 | |||
|         void addListener(TYPE f) { | |||
|             mList.push_back(f); | |||
|         } | |||
| 
 | |||
|         /*virtual void notify(void) {
 | |||
|             for(typename std::list<TYPE>::iterator it = mList.begin(); it != mList.end(); ++it) { | |||
|                (*it)(); | |||
|             } | |||
|         }*/ | |||
| 
 | |||
|     protected: | |||
|         std::list<TYPE> mList; | |||
| }; | |||
| 
 | |||
| #endif /*__HANDLER_H__*/ | |||
| @ -1,110 +0,0 @@ | |||
| //-----------------------------------------------------------------------------
 | |||
| // 2022 Ahoy, https://ahoydtu.de
 | |||
| // Lukas Pusch, lukas@lpusch.de
 | |||
| // Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
 | |||
| //-----------------------------------------------------------------------------
 | |||
| #ifndef __LIST_H__ | |||
| #define __LIST_H__ | |||
| 
 | |||
| template<class T, class... Args> | |||
| struct node_s { | |||
|     typedef T dT; | |||
|     node_s *pre; | |||
|     node_s *nxt; | |||
|     uint8_t id; | |||
|     dT d; | |||
|     node_s() : pre(NULL), nxt(NULL), d() {} | |||
|     node_s(Args... args) : id(0), pre(NULL), nxt(NULL), d(args...) {} | |||
| }; | |||
| 
 | |||
| template<int MAX_NUM, class T, class... Args> | |||
| class llist { | |||
|     typedef node_s<T, Args...> elmType; | |||
|     typedef T dataType; | |||
|     public: | |||
|         llist() : root(mPool) { | |||
|             root = NULL; | |||
|             elmType *p = mPool; | |||
|             for(uint32_t i = 0; i < MAX_NUM; i++) { | |||
|                 p->id = i; | |||
|                 p++; | |||
|             } | |||
|             mFill = mMax = 0; | |||
|         } | |||
| 
 | |||
|         elmType *add(Args... args) { | |||
|             elmType *p = root, *t; | |||
|             if(NULL == (t = getFreeNode())) | |||
|                 return NULL; | |||
|             if(++mFill > mMax) | |||
|                 mMax = mFill; | |||
| 
 | |||
|             if(NULL == root) { | |||
|                 p = root = t; | |||
|                 p->pre = p; | |||
|                 p->nxt = p; | |||
|             } | |||
|             else { | |||
|                 p = root->pre; | |||
|                 t->pre = p; | |||
|                 p->nxt->pre = t; | |||
|                 t->nxt = p->nxt; | |||
|                 p->nxt = t; | |||
|             } | |||
|             t->d = dataType(args...); | |||
|             return p; | |||
|         } | |||
| 
 | |||
|         elmType *getFront() { | |||
|             return root; | |||
|         } | |||
| 
 | |||
|         elmType *get(elmType *p) { | |||
|             p = p->nxt; | |||
|             return (p == root) ? NULL : p; | |||
|         } | |||
| 
 | |||
|         elmType *rem(elmType *p) { | |||
|             if(NULL == p) | |||
|                 return NULL; | |||
|             elmType *t = p->nxt; | |||
|             p->nxt->pre = p->pre; | |||
|             p->pre->nxt = p->nxt; | |||
|             if((root == p) && (p->nxt == p)) | |||
|                 root = NULL; | |||
|             else | |||
|                 root = p->nxt; | |||
|             p->nxt = NULL; | |||
|             p->pre = NULL; | |||
|             p = NULL; | |||
|             mFill--; | |||
|             return (NULL == root) ? NULL : ((t == root) ? NULL : t); | |||
|         } | |||
| 
 | |||
|         uint16_t getFill(void) { | |||
|             return mFill; | |||
|         } | |||
| 
 | |||
|         uint16_t getMaxFill(void) { | |||
|             return mMax; | |||
|         } | |||
| 
 | |||
|     protected: | |||
|         elmType *root; | |||
| 
 | |||
|     private: | |||
|         elmType *getFreeNode(void) { | |||
|             elmType *n = mPool; | |||
|             for(uint32_t i = 0; i < MAX_NUM; i++) { | |||
|                 if(NULL == n->nxt) | |||
|                     return n; | |||
|                 n++; | |||
|             } | |||
|             return NULL; | |||
|         } | |||
| 
 | |||
|         elmType mPool[MAX_NUM]; | |||
|         uint16_t mFill, mMax; | |||
| }; | |||
| 
 | |||
| #endif /*__LIST_H__*/ | |||
					Loading…
					
					
				
		Reference in new issue