mirror of
https://github.com/letscontrolit/ESPEasy.git
synced 2026-07-28 04:07:47 +00:00
Merge branch 'mega' of https://github.com/letscontrolit/ESPEasy into feature/TLS-update-bearssl-cp
This commit is contained in:
+10
-3
@@ -5,7 +5,7 @@
|
||||
#############################################################################################################
|
||||
# This script parses all documentation substitution files to determine in what builds a plugin is available
|
||||
# Collection A..G, Display, Energy and Neopixel, IR and IRext get Normal plugins injected
|
||||
# Collection plugins are also injected into Collection A..G
|
||||
# Collection, Notify and Network plugins are also injected into Collection A..G
|
||||
# All plugins get injected into MAX build set
|
||||
# Some build sets have exceptions for plugins not available
|
||||
# The output generation order is determined by how they are ordered in list 'buildColors'
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
# Changelog:
|
||||
# 2025-10-05 tonhuisman: Adjustments for Display A and Display B split
|
||||
# 2025-10-01 tonhuisman: Include Notify and Network plugins, ignore not available files, parse NWxxx also
|
||||
# 2024-05-04 tonhuisman: Working and documented
|
||||
# 2024-04-28 tonhuisman: Initial script
|
||||
|
||||
@@ -44,7 +45,7 @@ excludePlugins = {
|
||||
'CLIMATE': {'P007', 'P008', 'P009', 'P017', 'P022', 'P027', 'P030', 'P035', 'P040', 'P041', 'P042', 'P045'},
|
||||
'DISPLAY A': {'P038', 'P041', 'P042', 'P070'},
|
||||
'DISPLAY B': {'P038', 'P041', 'P042', 'P057', 'P070', 'P075', 'P104'},
|
||||
'MAX': {'P089'},
|
||||
# 'MAX': {''},
|
||||
# 'NEOPIXEL': {''},
|
||||
'NORMAL': {'P016', 'P035'},
|
||||
}
|
||||
@@ -105,6 +106,8 @@ def addToAllBuilds(plugin, pluginName, builds:dict):
|
||||
# Parse a single substitution file
|
||||
def parseSingleSubstitutionFile(fileName):
|
||||
filepath = os.path.relpath(os.path.join(basePath, fileName), '.')
|
||||
if not os.path.isfile(filepath):
|
||||
return
|
||||
# print(filepath) # For debugging
|
||||
pfile = open(filepath, "r")
|
||||
# Start empty
|
||||
@@ -117,7 +120,7 @@ def parseSingleSubstitutionFile(fileName):
|
||||
break
|
||||
# Parse into label, plugin ID, description and up to 4 separate builds (current max.),
|
||||
# append "(?:[^`]+`([^`]+)`)?" to regex for an extra build, if needed
|
||||
m = re.search(r"[^|]\|([PCN](\d{3}))([^\|]+)\|[^`]+`([^`]+)`(?:[^`]+`([^`]+)`)?(?:[^`]+`([^`]+)`)?(?:[^`]+`([^`]+)`)?", line)
|
||||
m = re.search(r"[^|]\|((?:NW|[PCN])(\d{3}))([^\|]+)\|[^`]+`([^`]+)`(?:[^`]+`([^`]+)`)?(?:[^`]+`([^`]+)`)?(?:[^`]+`([^`]+)`)?", line)
|
||||
if m:
|
||||
if m.group(3) == "_typename": # the typename substitution should be before _status...
|
||||
if plugin != "" and plugin != m.group(1): # Changed plugin ID, store current
|
||||
@@ -182,6 +185,10 @@ print('Parsing substitutions for build sets...')
|
||||
parseSubstitutionFiles('../Plugin/_plugin_substitutions.repl')
|
||||
# Parse all Controller substitutions
|
||||
parseSingleSubstitutionFile('../Controller/_controller_substitutions.repl')
|
||||
# Parse all Notify substitutions
|
||||
parseSingleSubstitutionFile('../Notify/_notify_substitutions_n00x.repl')
|
||||
# Parse all Network substitutions
|
||||
parseSingleSubstitutionFile('../Network/_network_substitutions.repl')
|
||||
|
||||
# Generate output
|
||||
generateBuildOverview('../Plugin/_plugin_sets_overview.repl')
|
||||
|
||||
@@ -1,6 +1,29 @@
|
||||
Supported ESP Chips
|
||||
*******************
|
||||
|
||||
ESP8266 is Feature Complete!
|
||||
============================
|
||||
|
||||
(Since 2025-04-30)
|
||||
|
||||
The core team has decided to declare the ESP8266 builds (that also support ESP8285) Feature Complete, for multiple reasons:
|
||||
|
||||
* **Binary size**: Making (new or enhanced) plugins and growing feature set fit in the limited available binary space of an ESP8266 (1020kB) is getting harder and harder. Many hundreds of hours have been spent already to reduce size as much as possble, and there isn't much room for improvement anymore.
|
||||
* **Limited RAM available**: The ESP8266 has only 80 kB of RAM available, and with the core of ESPEasy loaded, that leaves only between 15 and 25 kB of free memory for plugins to work with. This is a major cause for crashes when some complicated tasks are handling data of some size.
|
||||
* **Chip development progress**: New features for ESP chips are being developed, but the ESP8266 platform, while still being manufactured, does not get technical improvements anymore.
|
||||
* **Software support by Espressif**: New software development in the framework for supporting the ESP platform is only directed at the ESP32 line of MCUs. No new development for ESP8266 is being done.
|
||||
|
||||
The consequences of this decision are that:
|
||||
|
||||
* New plugins and features are **not** included in the regularly made available ESP8266 builds.
|
||||
* To enable some of the new features (many are still useable) for ESP8266, a Custom build can be configured and built by the user, as documented in :ref:`PlatformIO_page`.
|
||||
* A notable exception is support for TLS: That's *not* possible to enable on ESPEasy in ESP8266 builds as it doesn't fit in the limited available RAM memory.
|
||||
|
||||
For new projects, it is strongly advised to select one of the many available ESP32 boards, or chips when designing a custom board. Some of the ESP32 variants are available with 16 MB Flash (ESP32 Classic, ESP32-C3, ESP32-C6 and ESP32-S3), and have 1 or more MAX builds available in ESPEasy, that include all plugins and features available, and also a larger selection of fonts for displays (TFT/LCD, OLed and 7-segment).
|
||||
|
||||
Overview of supported chips
|
||||
===========================
|
||||
|
||||
ESPEasy does support a number of variants of the processors manufactured by Espressif.
|
||||
|
||||
* **ESP8266** The original ESP processor, with external flash.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
.. _N001_page:
|
||||
|
||||
Notifications Email (SMTP)
|
||||
===========================
|
||||
|N001_typename|
|
||||
===============================
|
||||
|
||||
|N001_shortinfo|
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
.. _N002_page:
|
||||
|
||||
Notifications Buzzer
|
||||
=====================
|
||||
|N002_typename|
|
||||
========================
|
||||
|
||||
|N002_shortinfo|
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.. |N001_type| replace:: :cyan:`Notifications`
|
||||
.. |N001_name| replace:: :cyan:`Notifications Email (SMTP)`
|
||||
.. |N001_name| replace:: :cyan:`Notifications - Email (SMTP)`
|
||||
.. |N001_typename| replace:: :cyan:`Notifications - Email (SMTP)`
|
||||
.. |N001_porttype| replace:: `.`
|
||||
.. |N001_status| replace:: :green:`NORMAL` :yellow:`CLIMATE` :yellow:`COLLECTION` :yellow:`SONOFF` :yellow:`SHELLY`
|
||||
@@ -11,7 +11,7 @@
|
||||
.. |N001_page| replace:: N001
|
||||
|
||||
.. |N002_type| replace:: :cyan:`Notifications`
|
||||
.. |N002_name| replace:: :cyan:`Notifications Buzzer`
|
||||
.. |N002_name| replace:: :cyan:`Notifications - Buzzer`
|
||||
.. |N002_typename| replace:: :cyan:`Notifications - Buzzer`
|
||||
.. |N002_porttype| replace:: `.`
|
||||
.. |N002_status| replace:: :green:`NORMAL` :yellow:`CLIMATE` :yellow:`COLLECTION` :yellow:`SONOFF` :yellow:`SHELLY`
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
MQTT Device class
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
(Only available if both MQTT Auto Discovery and Device Class features are included in the build.)
|
||||
|
||||
* **MQTT Device class**: Select the Binary Device class that's to be used for this task device. Device classes marked with ``²`` are 'two-way' devices, meaning that the state will be updated when changed, either on the ESPEasy side, or on the MQTT (Home Assistant) side.
|
||||
|
||||
The default value used is ``power``, also when not set (empty), and can be updated in Home Assistant by resending the MQTT Discovery.
|
||||
|
||||
The available options are based on the Summer 2025 version of this `Home Assistant MQTT Binary sensor documentation page <https://www.home-assistant.io/integrations/binary_sensor/#device-class>`_
|
||||
|
||||
The On/Off icon shown in Home Assistant (HA) can be changed for an alternative in the HA configuration, after Auto Discovery has created the device there.
|
||||
@@ -1,4 +1,4 @@
|
||||
.. include:: ../Plugin/_plugin_substitutions_p00x.repl
|
||||
.. include:: ../Plugin/_plugin_substitutions_p00x.repl
|
||||
.. _P001_page:
|
||||
|
||||
|P001_typename|
|
||||
@@ -25,6 +25,9 @@ Supported hardware
|
||||
|
||||
|P001_usedby|
|
||||
|
||||
|
||||
.. include:: DeviceClass_binary.repl
|
||||
|
||||
Commands available
|
||||
------------------
|
||||
|
||||
|
||||
@@ -437,10 +437,12 @@ Change log
|
||||
.. versionchanged:: 2.0
|
||||
...
|
||||
|
||||
|improved| 2020-04-25 Added support for ESP32 ADC pins + Hall Effect Sensor.
|
||||
|improved| 2022-07-11 Added ESP32 Factory calibration, multipoint processing, binning and charts.
|
||||
|improved| 2022-07-27 Improved resolution when using ESP32 Factory Calibration.
|
||||
|
||||
|improved| 2022-07-11 Added ESP32 Factory calibration, multipoint processing, binning and charts.
|
||||
|
||||
|improved| 2020-04-25 Added support for ESP32 ADC pins + Hall Effect Sensor.
|
||||
|
||||
.. versionadded:: 1.0
|
||||
...
|
||||
|
||||
|
||||
@@ -110,6 +110,8 @@ Advanced event management
|
||||
|
||||
* **Use safe button (slower)**: This effectively adds an extra De-bounce delay and sends event value ``4`` when reached.
|
||||
|
||||
.. include:: DeviceClass_binary.repl
|
||||
|
||||
.. include:: DataAcquisition.repl
|
||||
|
||||
* **Interval** By default, Interval will be set to 60 sec. It is the frequency used to read sensor values and send these to any Controllers configured for this device.
|
||||
|
||||
@@ -112,6 +112,8 @@ Advanced event management
|
||||
|
||||
* **Use safe button (slower)**: This effectively adds an extra De-bounce delay and sends event value ``4`` when reached.
|
||||
|
||||
.. include:: DeviceClass_binary.repl
|
||||
|
||||
.. include:: DataAcquisition.repl
|
||||
|
||||
* **Interval** By default, Interval will be set to 60 sec. It is the frequency used to read sensor values and send these to any Controllers configured for this device.
|
||||
|
||||
@@ -136,6 +136,8 @@ Sensor
|
||||
|
||||
* **Auto-save interval** Here a time in minutes can be set after which any changed 'Set Level' via the ``config,task,<taskname>,SetLevel,<value>`` command will be saved. This *requires* that the above setting **Save 'Set Level' after change via config command** is **disabled**! When used, a setting of ca. 30 minutes, or even longer when the Set Level is changed often, seems apropriate, unless the unit often reboots, but then that cause should be investigated and solved. The timer, when activated, should survive a warm reboot.
|
||||
|
||||
.. warning:: Saving settings too often will cause damage to the Flash memory of the unit!
|
||||
|
||||
* **Extended functionality**:sup:`1)` Enable new functionality. Changing this will reload the form showing/hiding the new options below.
|
||||
|
||||
* **Long time span**:sup:`1)` Timer values are per default entered in [seconds], enabling this option timing settings are tuned to long intervals using [hours] or [seconds]. Changing this will reload the form showing rescaled values and new units.
|
||||
@@ -160,6 +162,8 @@ Sensor
|
||||
|
||||
:sup:`1)` Configuration may not be available due to build size limitations.
|
||||
|
||||
.. include:: DeviceClass_binary.repl
|
||||
|
||||
.. include:: DataAcquisition.repl
|
||||
|
||||
Values
|
||||
|
||||
@@ -54,7 +54,7 @@ Description
|
||||
This Plugin reads the data from Thermocouples and Resistor Temperature Detector sensors. You have to use an Adapter Board with a respective
|
||||
adapter/converter in order to read the values. Take a look at the usual sources to find such boards.
|
||||
|
||||
You can only use ESP8266 boards which expose the SPI Interface. This Plugin uses only the Hardware SPI Interface - no software SPI at the moment.
|
||||
You can use any board which expose the SPI Interface. This Plugin uses only the selected SPI Interface.
|
||||
Nevertheless you need at least 3 Pins to use SPI. So using an very simple ESP-01 is unfortunately no option.
|
||||
|
||||
**Basic Information on Thermocouples**
|
||||
@@ -68,7 +68,7 @@ Wiring
|
||||
|
||||
Basic Information on SPI Bus you can find in `Wikipedia: SPI Bus <https://en.wikipedia.org/wiki/Serial_Peripheral_Interface>`_
|
||||
|
||||
You need an ESP8266 device with accessible SPI Pins. These Pins are:
|
||||
You need an **ESP8266** device with accessible SPI Pins. These Pins are:
|
||||
|
||||
==== ============= ====== ======== =========================================================================
|
||||
Name Description PIO NodeMCU Notes
|
||||
@@ -81,6 +81,8 @@ CS Chip Select GPIO15 D8 Hardware SPI (CS is configurable through
|
||||
|
||||
.. note:: Write Access to device registers is required for MAX 31856 and MAX 31865 devices so far.
|
||||
|
||||
For **ESP32** you can use any VSPI, HSPI or User Defined configuration, as the GPIO multiplexer in ESP32 chips can handle any GPIO pin with Input and Output capability for SPI.
|
||||
|
||||
Supported Hardware
|
||||
------------------
|
||||
|
||||
|
||||
+223
-1
@@ -24,7 +24,7 @@ Used libraries: |P102_usedlibraries|
|
||||
Description
|
||||
-----------
|
||||
|
||||
PZEM-004T V3.0 or Version 3.0 is the upgraded version to replace the old PZEM004T V1.0.
|
||||
PZEM-004T (AC) V3.0 or Version 3.0 is the upgraded version to replace the old PZEM004T V1.0.
|
||||
The old version has been sold out in most of the online store and is no longer being produced.
|
||||
|
||||
Improvements over V1:
|
||||
@@ -99,18 +99,238 @@ Active Energy
|
||||
* Resolution: 1Wh
|
||||
* Measurement accuracy: 0.5%
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
PZEM-017 v1.0/v2.0 (DC) For measuring DC loads. When the voltage is below 7V, an independent (**not from PC USB port!**) USB powersupply should be used on the USB input connector.
|
||||
|
||||
Specifications
|
||||
--------------
|
||||
|
||||
Voltage
|
||||
^^^^^^^
|
||||
|
||||
* Measuring range: 0.05 - 300V
|
||||
* Resolution: 0.01V
|
||||
* Measurement accuracy: 1%
|
||||
|
||||
Current
|
||||
^^^^^^^
|
||||
|
||||
* Measuring range:
|
||||
|
||||
* 0.02 - 50/100/200/300A(Depending on shunt)
|
||||
|
||||
* Resolution: 0.01A
|
||||
|
||||
* Measurement accuracy: 1%
|
||||
|
||||
|
||||
Active power
|
||||
^^^^^^^^^^^^
|
||||
|
||||
* Measuring range:
|
||||
|
||||
* 0.2 - 90kW(Depending on shunt)
|
||||
|
||||
* Starting measure power: 0.2W
|
||||
* Resolution: 0.1W
|
||||
* Measurement accuracy: 1%
|
||||
|
||||
|
||||
Active Energy
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
* Measuring range: 0 - 9999.99kWh
|
||||
* Resolution: 1Wh
|
||||
* Measurement accuracy: 1%
|
||||
|
||||
Installation and configuration
|
||||
------------------------------
|
||||
|
||||
When installing multiple PZEM devices on a single ESP unit, some specific order of configuration is required to be able to correctly configure a second, third, etc. PZEM.
|
||||
|
||||
This is described below, in the :cyan:`Installing multiple PZEM units on a single ESP` paragraph.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
.. image:: P102_DeviceConfiguration.png
|
||||
|
||||
Task Settings
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
* **Name**: Required by ESPEasy, must be unique among the list of available devices/tasks.
|
||||
|
||||
* **Enabled**: The device can be disabled or enabled. When not enabled the device should not use any resources.
|
||||
|
||||
Sensor
|
||||
^^^^^^
|
||||
|
||||
See: :ref:`SerialHelper_page`
|
||||
|
||||
Device Settings
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
* **PZEM Model**: Select the PZEM model that is to be handled by this task. (For changing the Address the model doesn't matter as they use the same command.)
|
||||
|
||||
Available options:
|
||||
|
||||
* *PZEM-004Tv30 (AC)*: The AC model, and default setting.
|
||||
* *PZEM-017v1 (DC)*: The DC model. Also compatible with later v2/2.0 models.
|
||||
|
||||
For reading the correct values from a PZEM-017, that Model *must* be selected as it uses a different data format to fetch the results.
|
||||
|
||||
PZEM Actions
|
||||
^^^^^^^^^^^^
|
||||
|
||||
* **PZEM Mode**: By default, the ``Read value`` option is selected.
|
||||
|
||||
Available options:
|
||||
|
||||
* *Read value*: Normal operating mode, for reading the configured values from the PZEM.
|
||||
* *Reset Energy*: For resetting the counted total energy, this option can be selected. See below for a description.
|
||||
* *Program address*: Only available on the *first* PZEM device, for changing the PZEM unit MODBUS address, as described below.
|
||||
|
||||
|
|
||||
|
||||
* **Address of PZEM**: Set to the address of the PZEM unit to be used. When only a single device is connected, can be set to 0, as a sort of 'universal' address.
|
||||
|
||||
Available address range for the *first* PZEM device: 0 .. 247, on subsequent PZEM devices: 1 .. 247.
|
||||
|
||||
Output Configuration
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
For all 4 available Values slots for this task, a value to use can be selected here. The available options depend om the **PZEM Model** setting:
|
||||
|
||||
* *Voltage_V*
|
||||
* *Current_A*
|
||||
* *Power_W*
|
||||
* *Energy_kWh*
|
||||
* *Power_Factor_cosphi*: for ``PZEM-004Tv30 (AC)`` only.
|
||||
* *Frequency_Hz*: for ``PZEM-004Tv30 (AC)`` only.
|
||||
|
||||
.. include:: DataAcquisition.repl
|
||||
|
||||
* **Interval**: By default, Interval will be set to 60 sec for this plugin. It is the frequency used to read sensor values and send these to any Controllers configured for this device.
|
||||
|
||||
Values
|
||||
^^^^^^
|
||||
|
||||
The measured values are configured above, and get their names based on the selection made there.
|
||||
|
||||
For a complete description of all available columns see the `Plugin - Values <_Plugin.html#values>`_ section.
|
||||
|
||||
|
|
||||
|
||||
|
||||
.. Events
|
||||
.. ~~~~~~
|
||||
|
||||
.. .. include:: P102_events.repl
|
||||
|
||||
Resetting the Energy counter
|
||||
----------------------------
|
||||
|
||||
For resetting the counted Energy value in the PZEM unit, there are 2 methods:
|
||||
|
||||
1. Use the *Reset Energy* **PZEM Mode** setting.
|
||||
2. Send the command ``resetenergy,<modbus_address>`` to the ESP unit. This can be done via the Command entry on the Tools page, from Rules, or via a url command as shown in the configuration page.
|
||||
|
||||
Use the *Reset Energy* **PZEM Mode** setting
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
For resetting the incrementing Energy counter in the PZEM unit, this PZEM Mode option can be used.
|
||||
|
||||
* Set **PZEM Mode** to ``Reset Energy``, and :cyan:`Submit` the page.
|
||||
|
||||
The command will be executed immediately, and afterward the status will shown:
|
||||
|
||||
.. image:: P102_ResetEnergyDone.png
|
||||
|
||||
The blue message showing that the command was sent. The **PZEM Mode** is already reset to ``Read value``.
|
||||
|
||||
To store this change in settings, the :cyan:`Submit` button should be used once more (you can of course change more settings if desired, that's why no automatic save is done.)
|
||||
|
||||
Send the ``resetenergy,<modbus_address>`` command
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
For an easy alternative to reset the Energy counter, you can use the ``resetenergy,<modbus_address>`` command, f.e. from the ``Command`` field on the Tools page, to reset the counter for the specific modbus address (range 1..247, or 0 if only 1 device is on the bus).
|
||||
|
||||
Installing multiple PZEM units on a single ESP
|
||||
----------------------------------------------
|
||||
|
||||
Configuring separate MODBUS addresses on each device
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To uniquely identify each PZEM unit on the bus, it has to be configured to use a unique address. The range of these addresses is 1 .. 247.
|
||||
|
||||
* Add the, numerically, first PZEM task, f.e. in Devices slot 1.
|
||||
|
||||
* Configure the serial port, and on ESP32 also the GPIO pins, to be used, enable the plugin, and connect a single PZEM to the RS485 converter. When using ``HW Serial0``, the Serial Console Settings, on the Tools/Advanced page, have to be disabled to avoid issues with his port.
|
||||
|
||||
* Set **PZEM Mode** to ``Program address`` and :cyan:`Submit` the page.
|
||||
|
||||
.. image:: P102_ProgramAddress.png
|
||||
|
||||
Fill the desired address in the **Address of PZEM** field, change the **Confirm address programming ?** field to ``YES``, and again :cyan:`Submit` the page.
|
||||
|
||||
When successful, a message :green:`Address programming done !` is displayed, and the **PZEM Mode** is set to the default ``Read value`` setting.
|
||||
|
||||
* Disconnect the PZEM unit from the RS485 bus, connect the next PZEM unit, and repeat above steps, using a diferent **Address of PZEM** value, for all units to be connected.
|
||||
|
||||
N.B.: The last set Address of PZEM will be kept in the configuration, but can be changed to the desired first PZEM unit.
|
||||
|
||||
N.B.2: To correctly store the **PZEM Mode** setting, the configuration should be saved once more, using the :cyan:`Submit` button!
|
||||
|
||||
Configuring a secondary PZEM unit
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The first PZEM unit can be configured as shown above in the generic Configuration paragraph. Once thats completed, with the correct, unique, MODBUS Address set, both in all PZEM units to connect and the task configuration for the first PZEM task, that task should be Enabled, so the next task added can detect that it will be the second (or third, etc.) device on the MODBUS chain.
|
||||
|
||||
After that task is running, a new PZEM task can be added, with a task number higher than the *first* PZEM task.
|
||||
|
||||
.. warning:: This is crucial for the PZEM tasks to start correctly, and in the correct order, on reboot or power-up of the ESP!
|
||||
|
||||
These secondary PZEM tasks do not use the Serial configuration, as they use the same connection as the *first* PZEM task.
|
||||
|
||||
.. image:: P102_SecondConfiguration.png
|
||||
|
||||
Sensor
|
||||
^^^^^^
|
||||
|
||||
This selector should not be used, as it is ignored.
|
||||
|
||||
Device Settings
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
* **PZEM Model**: Select the PZEM model that is to be handled by this task. (Changing the selection will save the new setting and reload the page.)
|
||||
|
||||
For reading the correct values from a PZEM-017, that Model *must* be selected as it uses a different data format to fetch the results.
|
||||
|
||||
PZEM Actions
|
||||
^^^^^^^^^^^^
|
||||
|
||||
* **PZEM Mode**: By default, the ``Read value`` option is selected.
|
||||
|
||||
Available options:
|
||||
|
||||
* *Read value*: Normal operating mode, for reading the configured values from the PZEM.
|
||||
* *Reset Energy*: For resetting the counted total energy, this option can be selected. See above for a description.
|
||||
|
||||
* **Address of PZEM**: Set to the address of the PZEM unit to be used.
|
||||
|
||||
Available address range: 1 .. 247.
|
||||
|
||||
When using the same address as the *first* PZEM task, and the **PZEM Model** connected is a ``PZEM-004Tv30 (AC)``, the extra values ``Power_Factor_cosphi`` and ``Frequency_Hz`` can be made available in a task, for sending to a controller.
|
||||
|
||||
|
|
||||
|
||||
Commands
|
||||
--------
|
||||
|
||||
.. include:: P102_commands.repl
|
||||
|
||||
|
||||
|
||||
Change log
|
||||
@@ -119,4 +339,6 @@ Change log
|
||||
.. versionchanged:: 2.0
|
||||
...
|
||||
|
||||
|added| 2025-08-06: Support for PZEM-017, updated documentation.
|
||||
|
||||
|added| 2020-04-25
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 82 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
@@ -0,0 +1,15 @@
|
||||
.. csv-table::
|
||||
:header: "Command Syntax", "Extra information"
|
||||
:widths: 20, 30
|
||||
|
||||
"
|
||||
|
||||
| ``ResetEnergy,<modbus_address>``
|
||||
|
||||
","
|
||||
|
||||
| This command will reset the Energy counter for the PZEM unit (value is stored in the unit). The value retrieved on the next read should return the updated value. (Can be 0 if no energy is flowing, or the energy counted since the reset command was executed.)
|
||||
|
||||
| This command can be executed by any task if multiple PZEM tasks are configured, as they all share the single MODBUS Serial configuration of the *first* PZEM task.
|
||||
|
||||
"
|
||||
@@ -27,6 +27,8 @@ Description
|
||||
Detecting (human) presence can be achieved in several ways, like via IR detection sensors, or a light-beam that's interrupted by someone passing. But these sensors have quite some limitations, like limited sensitivity, no information about the distance, or weather a person is there but not moving.
|
||||
|
||||
The limitations of these existing sensors are not applicable when using radar-based presence detection, and since some time, rather affordable radar human-presence detectors are available. These are available with 5 GHz, 10 GHz, 24 GHz and 60 GHz radar frequency transmitter/receiver chips. Because of the accuracy and range, achievable with 24 GHz sensors, these are quite popular, so support has been added to ESPEasy.
|
||||
Some notes about "false positive" detections: based on our test and experience some false positive presence detections can happens. For example if the sensor is near to plant, the movement of leaves can be incorrectly translated as presence detection; also electric cables in front of the sensor can provide noise to the sensor. To avoid false positive presence detection try to leave the sensor as free from obstacles as possible.
|
||||
|
||||
|
||||
Some examples of these sensors:
|
||||
|
||||
|
||||
@@ -324,7 +324,7 @@ There are different released versions of ESP Easy:
|
||||
|
||||
:red:`DEVELOPMENT` is used for plugins that are still being developed and are not considered stable at all. Currently there are no DEVELOPMENT builds available.
|
||||
|
||||
:yellow:`ENERGY` :yellow:`DISPLAY` :yellow:`IR` :yellow:`IRext` :yellow:`NEOPIXEL` :yellow:`CLIMATE` are specialized builds holding all Energy-, Display-, Infra Red- (extended), NeoPixel- and Climate- related plugins.
|
||||
:yellow:`ENERGY` :yellow:`DISPLAY` (split into sets A..B) :yellow:`IR` :yellow:`IRext` :yellow:`NEOPIXEL` :yellow:`CLIMATE` are specialized builds holding all Energy-, Display-, Infra Red- (extended), NeoPixel- and Climate- related plugins.
|
||||
|
||||
:yellow:`MAX` is the build that has all plugins that are available in the ESPEasy repository. Available for ESP32 16MB and ESP32 8MB Flash units (available for ESP32 Classic, ESP32-S3 and ESP32-C6).
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
.. |Plugin_Display| replace:: :ref:`P012_page`, :ref:`P023_page`, :ref:`P036_page`, :ref:`P057_page`, :ref:`P073_page`, :ref:`P075_page`, :ref:`P095_page`, :ref:`P104_page`, :ref:`P116_page`, :ref:`P131_page`, :ref:`P148_page`
|
||||
.. |Plugin_Distance| replace:: :ref:`P013_page`, :ref:`P110_page`, :ref:`P113_page`, :ref:`P134_page`
|
||||
.. |Plugin_Dust| replace:: :ref:`P018_page`, :ref:`P053_page`, :ref:`P056_page`, :ref:`P144_page`, :ref:`P175_page`
|
||||
.. |Plugin_Energy_AC| replace:: :ref:`P076_page`, :ref:`P077_page`, :ref:`P078_page`, :ref:`P102_page`, :ref:`P108_page`
|
||||
.. |Plugin_Energy_DC| replace:: :ref:`P027_page`, :ref:`P085_page`, :ref:`P115_page`, :ref:`P132_page`
|
||||
.. |Plugin_Energy_AC| replace:: :ref:`P076_page`, :ref:`P077_page`, :ref:`P078_page`, :ref:`P092_page`, :ref:`P102_page`, :ref:`P108_page`, :ref:`P176_page`
|
||||
.. |Plugin_Energy_DC| replace:: :ref:`P027_page`, :ref:`P085_page`, :ref:`P102_page`, :ref:`P115_page`, :ref:`P132_page`, :ref:`P176_page`
|
||||
.. |Plugin_Energy_Heat| replace:: :ref:`P088_page`, :ref:`P093_page`
|
||||
.. |Plugin_Environment| replace:: :ref:`P004_page`, :ref:`P005_page`, :ref:`P006_page`, :ref:`P014_page`, :ref:`P024_page`, :ref:`P028_page`, :ref:`P030_page`, :ref:`P031_page`, :ref:`P032_page`, :ref:`P034_page`, :ref:`P039_page`, :ref:`P047_page`, :ref:`P051_page`, :ref:`P068_page`, :ref:`P069_page`, :ref:`P072_page`, :ref:`P103_page`, :ref:`P105_page`, :ref:`P106_page`, :ref:`P122_page`, :ref:`P150_page`, :ref:`P151_page`, :ref:`P153_page`, :ref:`P154_page`, :ref:`P163_page`, :ref:`P167_page`, :ref:`P169_page`, :ref:`P172_page`, :ref:`P173_page`, :ref:`P177_page`
|
||||
.. |Plugin_Extra_IO| replace:: :ref:`P011_page`, :ref:`P022_page`, :ref:`P178_page`
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
.. |P093_name| replace:: :cyan:`Mitsubishi Heat Pump`
|
||||
.. |P093_type| replace:: :cyan:`Energy (Heat)`
|
||||
.. |P093_typename| replace:: :cyan:`Energy (Heat) - Mitsubishi Heat Pump`
|
||||
.. |P093_status| replace:: :yellow:`ENERGY` :yellow:`COLLECTION D`
|
||||
.. |P093_status| replace:: :yellow:`COLLECTION D` :yellow:`ENERGY`
|
||||
.. |P093_github| replace:: P093_MitsubishiHP.ino
|
||||
.. _P093_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P093_MitsubishiHP.ino
|
||||
.. |P093_usedby| replace:: `.`
|
||||
|
||||
@@ -24,18 +24,18 @@
|
||||
.. |P101_compileinfo| replace:: `.`
|
||||
.. |P101_usedlibraries| replace:: https://github.com/a7md0/WakeOnLan
|
||||
|
||||
.. |P102_name| replace:: :cyan:`PZEM-004Tv30-Multiple`
|
||||
.. |P102_type| replace:: :cyan:`Energy (AC)`
|
||||
.. |P102_typename| replace:: :cyan:`Energy (AC) - PZEM-004Tv30-Multiple`
|
||||
.. |P102_name| replace:: :cyan:`PZEM-004Tv30 / PZEM-017v1`
|
||||
.. |P102_type| replace:: :cyan:`Energy`
|
||||
.. |P102_typename| replace:: :cyan:`Energy - PZEM-004T (AC) / PZEM-017 (DC)`
|
||||
.. |P102_porttype| replace:: `.`
|
||||
.. |P102_status| replace:: :yellow:`ENERGY`
|
||||
.. |P102_github| replace:: P102_PZEM004Tv3.ino
|
||||
.. _P102_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P102_PZEM004Tv3.ino
|
||||
.. |P102_usedby| replace:: `.`
|
||||
.. |P102_shortinfo| replace:: `.`
|
||||
.. |P102_maintainer| replace:: TD-er
|
||||
.. |P102_maintainer| replace:: TD-er tonhuisman
|
||||
.. |P102_compileinfo| replace:: `.`
|
||||
.. |P102_usedlibraries| replace:: https://github.com/olehs/PZEM004T
|
||||
.. |P102_usedlibraries| replace:: https://github.com/olehs/PZEM004T https://github.com/mandulaj/PZEM-004T-v30
|
||||
|
||||
.. |P103_name| replace:: :cyan:`Atlas Scientific EZO pH ORP EC DO HUM`
|
||||
.. |P103_type| replace:: :cyan:`Environment`
|
||||
@@ -122,7 +122,7 @@
|
||||
.. |P108_type| replace:: :cyan:`Energy (AC)`
|
||||
.. |P108_typename| replace:: :cyan:`Energy (AC) - DDS238-x`
|
||||
.. |P108_porttype| replace:: `.`
|
||||
.. |P108_status| replace:: :yellow:`ENERGY` :yellow:`COLLECTION B`
|
||||
.. |P108_status| replace:: :yellow:`COLLECTION B` :yellow:`ENERGY`
|
||||
.. |P108_github| replace:: P108_DDS238.ino
|
||||
.. _P108_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P108_DDS238.ino
|
||||
.. |P108_usedby| replace:: `.`
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
.. |P115_type| replace:: :cyan:`Energy`
|
||||
.. |P115_typename| replace:: :cyan:`Energy - MAX1704x`
|
||||
.. |P115_porttype| replace:: `.`
|
||||
.. |P115_status| replace:: :yellow:`ENERGY` :yellow:`COLLECTION B`
|
||||
.. |P115_status| replace:: :yellow:`COLLECTION B` :yellow:`ENERGY`
|
||||
.. |P115_github| replace:: _P115_MAX1704x_v2.ino
|
||||
.. _P115_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P115_MAX1704x_v2.ino
|
||||
.. |P115_usedby| replace:: `.`
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
#define REG_PF 0x0008
|
||||
#define REG_ALARM 0x0009
|
||||
|
||||
#define REG_CURRENT 0x0001
|
||||
#define REG_HVALARM 0x0006
|
||||
#define REG_LVALARM 0x0007
|
||||
|
||||
#define CMD_RHR 0x03
|
||||
#define CMD_RIR 0X04
|
||||
#define CMD_WSR 0x06
|
||||
@@ -24,6 +28,9 @@
|
||||
#define WREG_ALARM_THR 0x0001
|
||||
#define WREG_ADDR 0x0002
|
||||
|
||||
#define WREG_HV_ALARM_THR 0x0000
|
||||
#define WREG_LV_ALARM_THR 0x0001
|
||||
|
||||
#define UPDATE_TIME 200
|
||||
|
||||
#define RESPONSE_SIZE 32
|
||||
@@ -84,6 +91,23 @@ PZEM004Tv30::~PZEM004Tv30()
|
||||
// delete this->_serial;
|
||||
}
|
||||
|
||||
|
||||
void PZEM004Tv30::setModel(PZEM_model model) {
|
||||
if (model == _model) {
|
||||
return;
|
||||
}
|
||||
_model = model;
|
||||
switch (_model) {
|
||||
case PZEM_model::PZEM004Tv30:
|
||||
_expectedResponse = PZEM004Tv30_EXPECTED_RESPONSE;
|
||||
_requestRegisters = PZEM004Tv30_REQUEST_REGISTERS;
|
||||
break;
|
||||
case PZEM_model::PZEM017Tv1:
|
||||
_expectedResponse = PZEM017v1_EXPECTED_RESPONSE;
|
||||
_requestRegisters = PZEM017v1_REQUEST_REGISTERS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*! * PZEM004Tv30::voltage *
|
||||
* Get line voltage in Volts *
|
||||
* @return current L-N volage*/
|
||||
@@ -222,28 +246,97 @@ uint8_t PZEM004Tv30::getAddress()
|
||||
* Set power alarm threshold in watts *
|
||||
* @param[in] watts Alamr theshold *
|
||||
* @return success*/
|
||||
bool PZEM004Tv30::setPowerAlarm(uint16_t watts)
|
||||
{
|
||||
if (watts > 25000){ // Sanitych check
|
||||
watts = 25000;
|
||||
}
|
||||
// bool PZEM004Tv30::setPowerAlarm(uint16_t watts)
|
||||
// {
|
||||
// if (watts > 25000){ // Sanitych check
|
||||
// watts = 25000;
|
||||
// }
|
||||
|
||||
// Write the watts threshold to the Alarm register
|
||||
if(!sendCmd8(CMD_WSR, WREG_ALARM_THR, watts, true))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
// // Write the watts threshold to the Alarm register
|
||||
// if(!sendCmd8(CMD_WSR, WREG_ALARM_THR, watts, true))
|
||||
// return false;
|
||||
// return true;
|
||||
// }
|
||||
|
||||
/*! * PZEM004Tv30::getPowerAlarm *
|
||||
* Is the power alarm set * *
|
||||
* @return arlam triggerd*/
|
||||
bool PZEM004Tv30::getPowerAlarm()
|
||||
{
|
||||
if(!updateValues()) // Update vales if necessary
|
||||
return NAN; // Update did not work, return NAN
|
||||
// bool PZEM004Tv30::getPowerAlarm()
|
||||
// {
|
||||
// if(!updateValues()) // Update vales if necessary
|
||||
// return NAN; // Update did not work, return NAN
|
||||
|
||||
// return _currentValues.alarms != 0x0000;
|
||||
// }
|
||||
|
||||
/*!
|
||||
* PZEM004Tv30::setHighVoltAlarm
|
||||
* Set HV alarm threshold in volts
|
||||
* @param[in] volt Alarm theshold
|
||||
* @return success */
|
||||
// bool PZEM004Tv30::setHighvoltAlarm(uint16_t volts)
|
||||
// {
|
||||
// if (volts < 500){ // Sanity check
|
||||
// volts = 500;
|
||||
// }
|
||||
|
||||
// if (volts > 34999){ // Sanity check
|
||||
// volts = 34999;
|
||||
// }
|
||||
|
||||
// // Write the volts threshold to the alarm register
|
||||
// if(!sendCmd8(CMD_WSR, WREG_HV_ALARM_THR, volts, true))
|
||||
// return false;
|
||||
|
||||
// return true;
|
||||
// }
|
||||
|
||||
/*!
|
||||
* PZEM004Tv30::setLowVoltAlarm
|
||||
* Set LV alarm threshold in volts
|
||||
* @param[in] volt Alarm theshold
|
||||
* @return success */
|
||||
// bool PZEM004Tv30::setLowvoltAlarm(uint16_t volts)
|
||||
// {
|
||||
// if (volts < 100){ // Sanity check
|
||||
// volts = 100;
|
||||
// }
|
||||
|
||||
// if (volts > 34999){ // Sanity check
|
||||
// volts = 34999;
|
||||
// }
|
||||
|
||||
// // Write the volts threshold to the alarm register
|
||||
// if(!sendCmd8(CMD_WSR, WREG_LV_ALARM_THR, volts, true))
|
||||
// return false;
|
||||
|
||||
// return true;
|
||||
// }
|
||||
|
||||
/*!
|
||||
* PZEM004Tv30::isHighVoltAlarmOn GET
|
||||
* Is the HV alarm set
|
||||
* @return alarm triggerd*/
|
||||
// bool PZEM004Tv30::isHighvoltAlarmOn()
|
||||
// {
|
||||
// if(!updateValues()) // Update vales if necessary
|
||||
// return NAN; // Update did not work, return NAN
|
||||
|
||||
// return _currentValues.HVAlarms != 0x0000;
|
||||
// }
|
||||
|
||||
/*!
|
||||
* PZEM004Tv30::isLowVoltAlarmOn GET
|
||||
* Is the LV alarm set
|
||||
* @return alarm triggerd*/
|
||||
// bool PZEM004Tv30::isLowvoltAlarmOn()
|
||||
// {
|
||||
// if(!updateValues()) // Update vales if necessary
|
||||
// return NAN; // Update did not work, return NAN
|
||||
|
||||
// return _currentValues.LVAlarms != 0x0000;
|
||||
// }
|
||||
|
||||
return _currentValues.alarms != 0x0000;
|
||||
}
|
||||
|
||||
/*! * PZEM004Tv30::init *
|
||||
* initialization common to all consturctors *
|
||||
@@ -266,52 +359,75 @@ void PZEM004Tv30::init(uint8_t addr){
|
||||
* @return success*/
|
||||
bool PZEM004Tv30::updateValues()
|
||||
{
|
||||
//static uint8_t buffer[] = {0x00, CMD_RIR, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00};
|
||||
static uint8_t response[25];
|
||||
|
||||
// If we read before the update time limit, do not update
|
||||
if(_lastRead + UPDATE_TIME > millis()){
|
||||
return true;
|
||||
}
|
||||
|
||||
// Read 10 registers starting at 0x00 (no check)
|
||||
sendCmd8(CMD_RIR, 0x00, 0x0A, false);
|
||||
// Read <model> registers starting at 0x00 (no check)
|
||||
sendCmd8(CMD_RIR, 0x00, _requestRegisters, false);
|
||||
|
||||
|
||||
if(recieve(response, 25) != 25){ // Something went wrong
|
||||
if(recieve(_response, _expectedResponse) != _expectedResponse){ // Something went wrong
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Update the current values
|
||||
_currentValues.voltage = ((uint32_t)response[3] << 8 | // Raw voltage in 0.1V
|
||||
(uint32_t)response[4])/10.0;
|
||||
switch(_model) {
|
||||
case PZEM_model::PZEM004Tv30:
|
||||
_currentValues.voltage = ((uint32_t)_response[3] << 8 | // Raw voltage in 0.1V
|
||||
(uint32_t)_response[4]) / 10.0;
|
||||
|
||||
_currentValues.current = ((uint32_t)response[5] << 8 | // Raw current in 0.001A
|
||||
(uint32_t)response[6] |
|
||||
(uint32_t)response[7] << 24 |
|
||||
(uint32_t)response[8] << 16) / 1000.0;
|
||||
_currentValues.current = ((uint32_t)_response[5] << 8 | // Raw current in 0.001A
|
||||
(uint32_t)_response[6] |
|
||||
(uint32_t)_response[7] << 24 |
|
||||
(uint32_t)_response[8] << 16) / 1000.0;
|
||||
|
||||
_currentValues.power = ((uint32_t)response[9] << 8 | // Raw power in 0.1W
|
||||
(uint32_t)response[10] |
|
||||
(uint32_t)response[11] << 24 |
|
||||
(uint32_t)response[12] << 16) / 10.0;
|
||||
_currentValues.power = ((uint32_t)_response[9] << 8 | // Raw power in 0.1W
|
||||
(uint32_t)_response[10] |
|
||||
(uint32_t)_response[11] << 24 |
|
||||
(uint32_t)_response[12] << 16) / 10.0;
|
||||
|
||||
_currentValues.energy = ((uint32_t)response[13] << 8 | // Raw Energy in 1Wh
|
||||
(uint32_t)response[14] |
|
||||
(uint32_t)response[15] << 24 |
|
||||
(uint32_t)response[16] << 16) / 1000.0;
|
||||
_currentValues.energy = ((uint32_t)_response[13] << 8 | // Raw Energy in 1Wh
|
||||
(uint32_t)_response[14] |
|
||||
(uint32_t)_response[15] << 24 |
|
||||
(uint32_t)_response[16] << 16) / 1000.0;
|
||||
|
||||
_currentValues.frequeny =((uint32_t)response[17] << 8 | // Raw Frequency in 0.1Hz
|
||||
(uint32_t)response[18]) / 10.0;
|
||||
_currentValues.frequeny =((uint32_t)_response[17] << 8 | // Raw Frequency in 0.1Hz
|
||||
(uint32_t)_response[18]) / 10.0;
|
||||
|
||||
_currentValues.pf = ((uint32_t)response[19] << 8 | // Raw pf in 0.01
|
||||
(uint32_t)response[20])/100.0;
|
||||
_currentValues.pf = ((uint32_t)_response[19] << 8 | // Raw pf in 0.01
|
||||
(uint32_t)_response[20]) / 100.0;
|
||||
|
||||
_currentValues.alarms = ((uint32_t)response[21] << 8 | // Raw alarm value
|
||||
(uint32_t)response[22]);
|
||||
_currentValues.alarms = ((uint32_t)_response[21] << 8 | // Raw alarm value
|
||||
(uint32_t)_response[22]);
|
||||
break;
|
||||
case PZEM_model::PZEM017Tv1:
|
||||
_currentValues.voltage = ((uint32_t)_response[3] << 8 | // Raw voltage in 0.01V
|
||||
(uint32_t)_response[4]) / 100.0;
|
||||
|
||||
_currentValues.current = ((uint32_t)_response[5] << 8 | // Raw voltage in 0.01A
|
||||
(uint32_t)_response[6]) / 100.0;
|
||||
|
||||
_currentValues.power = ((uint32_t)_response[7] << 8 | // Raw power in 0.1W
|
||||
(uint32_t)_response[8] |
|
||||
(uint32_t)_response[9] << 24 |
|
||||
(uint32_t)_response[10] << 16) / 10.0;
|
||||
|
||||
_currentValues.energy = ((uint32_t)_response[11] << 8 | // Raw Energy in 1Wh
|
||||
(uint32_t)_response[12] |
|
||||
(uint32_t)_response[13] << 24 |
|
||||
(uint32_t)_response[14] << 16) / 1000.0;
|
||||
|
||||
_currentValues.HVAlarms = ((uint32_t)_response[15] << 8 | // Raw alarm value
|
||||
(uint32_t)_response[16]);
|
||||
|
||||
_currentValues.LVAlarms = ((uint32_t)_response[17] << 8 | // Raw alarm value
|
||||
(uint32_t)_response[18]);
|
||||
break;
|
||||
}
|
||||
// Record current time as _lastRead
|
||||
_lastRead = millis();
|
||||
|
||||
|
||||
@@ -28,9 +28,20 @@
|
||||
#include <ESPeasySerial.h>
|
||||
#endif
|
||||
|
||||
#define PZEM004Tv30_EXPECTED_RESPONSE 25
|
||||
#define PZEM004Tv30_REQUEST_REGISTERS 10
|
||||
|
||||
#define PZEM017v1_EXPECTED_RESPONSE 21
|
||||
#define PZEM017v1_REQUEST_REGISTERS 8
|
||||
|
||||
#define PZEM_DEFAULT_ADDR 0xF8
|
||||
|
||||
#define PZEM_MAX_EXPECTED_RESPONSE 25 // PZEM004v30 needs this buffer size, adjust for models that need a bigger buffer
|
||||
|
||||
enum class PZEM_model : uint8_t {
|
||||
PZEM004Tv30 = 0, // Buffer size 25, request 10 registers
|
||||
PZEM017Tv1 = 1, // Buffer size 21, request 8 registers
|
||||
};
|
||||
|
||||
class PZEM004Tv30
|
||||
{
|
||||
@@ -40,6 +51,7 @@ public:
|
||||
#endif
|
||||
~PZEM004Tv30();
|
||||
|
||||
void setModel(PZEM_model model); // Sets some communication buffer params
|
||||
|
||||
float voltage();
|
||||
float current();
|
||||
@@ -52,8 +64,14 @@ public:
|
||||
bool setAddress(uint8_t addr);
|
||||
uint8_t getAddress();
|
||||
|
||||
bool setPowerAlarm(uint16_t watts);
|
||||
bool getPowerAlarm();
|
||||
// Unused methods:
|
||||
// bool setPowerAlarm(uint16_t watts);
|
||||
// bool getPowerAlarm();
|
||||
|
||||
// bool setHighvoltAlarm(uint16_t volts); //moja uprava
|
||||
// bool setLowvoltAlarm(uint16_t volts); //moja uprava
|
||||
// bool isHighvoltAlarmOn(); //upravil som
|
||||
// bool isLowvoltAlarmOn(); //upravil som
|
||||
|
||||
bool resetEnergy();
|
||||
void init(uint8_t addr); // Init common to all constructors
|
||||
@@ -64,15 +82,22 @@ private:
|
||||
bool _isSoft; // Is serial interface software
|
||||
|
||||
uint8_t _addr; // Device address
|
||||
PZEM_model _model = PZEM_model::PZEM004Tv30; // Current default
|
||||
|
||||
uint8_t _response[PZEM_MAX_EXPECTED_RESPONSE];
|
||||
uint8_t _expectedResponse = PZEM004Tv30_EXPECTED_RESPONSE;
|
||||
uint8_t _requestRegisters = PZEM004Tv30_REQUEST_REGISTERS;
|
||||
|
||||
struct {
|
||||
float voltage;
|
||||
float current;
|
||||
float power;
|
||||
float energy;
|
||||
float frequeny;
|
||||
float pf;
|
||||
uint16_t alarms;
|
||||
float frequeny; // PZEM004
|
||||
float pf; // PZEM004
|
||||
uint16_t alarms; // PZEM004
|
||||
uint16_t HVAlarms; //upravil som PZEM017
|
||||
uint16_t LVAlarms; //upravil sOM PZEM017
|
||||
} _currentValues; // Measured values
|
||||
|
||||
uint64_t _lastRead; // Last time values were updated
|
||||
|
||||
+78
-38
@@ -3,11 +3,15 @@
|
||||
#ifdef USES_P102
|
||||
|
||||
// #######################################################################################################
|
||||
// #################################### Plugin 102: PZEM004T v30 with modbus mgt##########################
|
||||
// ######################## Plugin 102: PZEM004Tv30 / PZEM-017v1 with modbus mgt ########################
|
||||
// #######################################################################################################
|
||||
//
|
||||
|
||||
/** Changelog:
|
||||
* 2025-09-14 tonhuisman: Add extra instruction to submit page once more after 'Reset energy' is used, to save 'Read energy' default Mode.
|
||||
* 2025-08-06 tonhuisman: Change plugin name to "Energy - PZEM-004T (AC) / PZEM-017 (DC)"
|
||||
* 2025-08-05 tonhuisman: Add support for PZEM-017v1 from a forum suggestion:
|
||||
* https://www.letscontrolit.com/forum/viewtopic.php?p=74069#p74064
|
||||
* 2025-01-17 tonhuisman: Implement support for MQTT AutoDiscovery (partially)
|
||||
* 2025-01-12 tonhuisman: Add support for MQTT AutoDiscovery (not supported yet for PZEM00x)
|
||||
*/
|
||||
@@ -21,7 +25,7 @@
|
||||
# define PLUGIN_102
|
||||
# define PLUGIN_ID_102 102
|
||||
# define PLUGIN_102_DEBUG true // activate extra log info in the debug
|
||||
# define PLUGIN_NAME_102 "Energy (AC) - PZEM-004Tv30-Multiple"
|
||||
# define PLUGIN_NAME_102 "Energy - PZEM-004T (AC) / PZEM-017 (DC)"
|
||||
|
||||
# define P102_PZEM_mode PCONFIG(1) // 0=read value ; 1=reset energy; 2=programm address
|
||||
# define P102_PZEM_ADDR PCONFIG(2)
|
||||
@@ -32,6 +36,7 @@
|
||||
# define P102_QUERY4 PCONFIG(6)
|
||||
# define P102_PZEM_FIRST PCONFIG(7)
|
||||
# define P102_PZEM_ATTEMPT PCONFIG_LONG(1)
|
||||
# define P102_PZEM_TYPE PCONFIG_LONG(0)
|
||||
|
||||
# define P102_PZEM_mode_DFLT 0 // Read value
|
||||
# define P102_QUERY1_DFLT 0 // Voltage (V)
|
||||
@@ -44,6 +49,10 @@
|
||||
|
||||
# define P102_PZEM_MAX_ATTEMPT 3 // Number of tentative before declaring NAN value
|
||||
|
||||
# define P102_PZEM004_VALUE_COUNT 6
|
||||
# define P102_PZEM017_VALUE_COUNT 4
|
||||
|
||||
|
||||
PZEM004Tv30 * P102_PZEM_sensor = nullptr;
|
||||
|
||||
boolean Plugin_102_init = false;
|
||||
@@ -56,7 +65,7 @@ const __FlashStringHelper* p102_getQueryString(uint8_t query);
|
||||
|
||||
boolean Plugin_102(uint8_t function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
bool success = false;
|
||||
|
||||
switch (function)
|
||||
{
|
||||
@@ -127,6 +136,7 @@ boolean Plugin_102(uint8_t function, struct EventStruct *even
|
||||
case PLUGIN_WEBFORM_SHOW_CONFIG:
|
||||
{
|
||||
string += serialHelper_getSerialTypeLabel(event);
|
||||
string += strformat(F("<BR>addr: 0x%02x"), P102_PZEM_ADDR); // Show modbus address
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
@@ -135,14 +145,17 @@ boolean Plugin_102(uint8_t function, struct EventStruct *even
|
||||
{
|
||||
// To select the data in the 4 fields.
|
||||
const __FlashStringHelper *options[P102_NR_OUTPUT_OPTIONS];
|
||||
const uint8_t nrOptions = PZEM_model::PZEM004Tv30 == static_cast<PZEM_model>(P102_PZEM_TYPE)
|
||||
? P102_PZEM004_VALUE_COUNT
|
||||
: P102_PZEM017_VALUE_COUNT;
|
||||
|
||||
for (uint8_t i = 0; i < P102_NR_OUTPUT_OPTIONS; ++i) {
|
||||
for (uint8_t i = 0; i < nrOptions; ++i) {
|
||||
options[i] = p102_getQueryString(i);
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < P102_NR_OUTPUT_VALUES; ++i) {
|
||||
const uint8_t pconfigIndex = i + P102_QUERY1_CONFIG_POS;
|
||||
sensorTypeHelper_loadOutputSelector(event, pconfigIndex, i, P102_NR_OUTPUT_OPTIONS, options);
|
||||
sensorTypeHelper_loadOutputSelector(event, pconfigIndex, i, nrOptions, options);
|
||||
}
|
||||
|
||||
success = true;
|
||||
@@ -150,7 +163,19 @@ boolean Plugin_102(uint8_t function, struct EventStruct *even
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD: {
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
{
|
||||
const __FlashStringHelper*pzemModels[] = {
|
||||
F("PZEM-004Tv30 (AC)"),
|
||||
F("PZEM-017v1 (DC)"),
|
||||
};
|
||||
constexpr int pzemCount = NR_ELEMENTS(pzemModels);
|
||||
FormSelectorOptions selector(pzemCount, pzemModels);
|
||||
selector.reloadonchange = true;
|
||||
selector.addFormSelector(F("PZEM Model"), F("pztype"), P102_PZEM_TYPE);
|
||||
}
|
||||
|
||||
if (P102_PZEM_sensor == nullptr) { P102_PZEM_FIRST = event->TaskIndex; // To detect if first PZEM or not
|
||||
}
|
||||
|
||||
@@ -161,7 +186,7 @@ boolean Plugin_102(uint8_t function, struct EventStruct *even
|
||||
"don't use HW serial (or invert Tx and Rx to configure as SW serial).</B></span>"));
|
||||
addFormSubHeader(F("PZEM actions"));
|
||||
{
|
||||
const __FlashStringHelper *options_model[] = { F("Read_value"), F("Reset_Energy"), F("Program_adress") };
|
||||
const __FlashStringHelper *options_model[] = { F("Read value"), F("Reset Energy"), F("Program address") };
|
||||
constexpr size_t optionCount = NR_ELEMENTS(options_model);
|
||||
const FormSelectorOptions selector(optionCount, options_model);
|
||||
selector.addFormSelector(F("PZEM Mode"), F("PZEM_mode"), P102_PZEM_mode);
|
||||
@@ -169,8 +194,8 @@ boolean Plugin_102(uint8_t function, struct EventStruct *even
|
||||
|
||||
if (P102_PZEM_mode == 2)
|
||||
{
|
||||
addHtml(F("<span style=\"color:red\"> <br>When programming an address, only one PZEMv30 must be connected. "
|
||||
"Otherwise, all connected PZEMv30s will get the same address, which would cause a conflict during reading.</span>"));
|
||||
addHtml(F("<span style=\"color:red\"> <br>When programming an address, only one PZEM must be connected. "
|
||||
"Otherwise, all connected PZEMs will get the same address, which would cause a conflict during reading.</span>"));
|
||||
{
|
||||
const __FlashStringHelper *options_confirm[] = { F("NO"), F("YES") };
|
||||
constexpr size_t optionCount = NR_ELEMENTS(options_confirm);
|
||||
@@ -182,13 +207,13 @@ boolean Plugin_102(uint8_t function, struct EventStruct *even
|
||||
}
|
||||
else
|
||||
{
|
||||
addFormNumericBox(F("Address of PZEM"), F("PZEM_addr"), P102_PZEM_ADDR, 0, 247);
|
||||
addHtml(F(" Address 0 allows to communicate with any <B>single</B> PZEMv30 whatever its address"));
|
||||
addFormNumericBox(F("Address of PZEM"), F("PZEM_addr"), P102_PZEM_ADDR, 0x00, 0xF7);
|
||||
addHtml(F(" Address 0 allows to communicate with any <B>single</B> PZEM whatever its address"));
|
||||
}
|
||||
|
||||
if (P102_PZEM_ADDR_SET == 3) // If address programming done
|
||||
{
|
||||
addHtml(F("<span style=\"color:green\"> <br><B>Address programming done ! </B></span>"));
|
||||
addHtml(F("<span style=\"color:green\"><br><B>Address programming done ! </B></span>"));
|
||||
P102_PZEM_ADDR_SET = 0; // Reset programming confirmation
|
||||
}
|
||||
}
|
||||
@@ -196,28 +221,30 @@ boolean Plugin_102(uint8_t function, struct EventStruct *even
|
||||
{
|
||||
addFormSubHeader(F("PZEM actions"));
|
||||
{
|
||||
const __FlashStringHelper *options_model[] = { F("Read_value"), F("Reset_Energy") };
|
||||
const __FlashStringHelper *options_model[] = { F("Read value"), F("Reset Energy") };
|
||||
constexpr size_t optionCount = NR_ELEMENTS(options_model);
|
||||
const FormSelectorOptions selector(optionCount, options_model);
|
||||
selector.addFormSelector(F("PZEM Mode"), F("PZEM_mode"), P102_PZEM_mode);
|
||||
}
|
||||
addHtml(F(" Tx/Rx Pins config disabled: Configuration is available in the first PZEM plugin.<br>"));
|
||||
addFormNumericBox(F("Address of PZEM"), F("PZEM_addr"), P102_PZEM_ADDR, 1, 247);
|
||||
addHtml(F(" Tx/Rx Pins config ignored: Configuration is available in the first PZEM plugin.<br>"));
|
||||
addFormNumericBox(F("Address of PZEM"), F("PZEM_addr"), P102_PZEM_ADDR, 0x01, 0xF7);
|
||||
}
|
||||
|
||||
addHtml(F("<br><br> Reset energy can be done also by: http://*espeasyip*/control?cmd=resetenergy,*PZEM address*"));
|
||||
|
||||
if (P102_PZEM_ADDR_SET == 4)
|
||||
{
|
||||
addHtml(F("<span style=\"color:blue\"> <br><B>Energy reset on current PZEM ! </B></span>"));
|
||||
addHtml(F("<span style=\"color:red\"> <br>Click <B>Submit</B> button once more to save 'Read value' PZEM Mode !</span>"));
|
||||
P102_PZEM_ADDR_SET = 0; // Reset programming confirmation
|
||||
}
|
||||
|
||||
addFormNote(F("Reset Energy can also be done by: http://*espeasyip*/control?cmd=resetenergy,*PZEM address*"));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SAVE: {
|
||||
case PLUGIN_WEBFORM_SAVE:
|
||||
{
|
||||
serialHelper_webformSave(event);
|
||||
|
||||
// Save output selector parameters.
|
||||
@@ -226,6 +253,7 @@ boolean Plugin_102(uint8_t function, struct EventStruct *even
|
||||
const uint8_t choice = PCONFIG(pconfigIndex);
|
||||
sensorTypeHelper_saveOutputSelector(event, pconfigIndex, i, p102_getQueryString(choice));
|
||||
}
|
||||
P102_PZEM_TYPE = getFormItemInt(F("pztype"));
|
||||
P102_PZEM_mode = getFormItemInt(F("PZEM_mode"));
|
||||
P102_PZEM_ADDR = getFormItemInt(F("PZEM_addr"));
|
||||
P102_PZEM_ADDR_SET = getFormItemInt(F("PZEM_addr_set"));
|
||||
@@ -263,6 +291,7 @@ boolean Plugin_102(uint8_t function, struct EventStruct *even
|
||||
|
||||
if (P102_PZEM_sensor != nullptr) {
|
||||
P102_PZEM_sensor->init(P102_PZEM_ADDR);
|
||||
P102_PZEM_sensor->setModel(static_cast<PZEM_model>(P102_PZEM_TYPE));
|
||||
|
||||
// Sequence for reseting PZEM energy
|
||||
if (P102_PZEM_mode == 1)
|
||||
@@ -297,6 +326,7 @@ boolean Plugin_102(uint8_t function, struct EventStruct *even
|
||||
{
|
||||
// When new data is available, return true
|
||||
P102_PZEM_sensor->init(P102_PZEM_ADDR);
|
||||
P102_PZEM_sensor->setModel(static_cast<PZEM_model>(P102_PZEM_TYPE));
|
||||
|
||||
float PZEM[6];
|
||||
PZEM[0] = P102_PZEM_sensor->voltage();
|
||||
@@ -306,12 +336,17 @@ boolean Plugin_102(uint8_t function, struct EventStruct *even
|
||||
PZEM[4] = P102_PZEM_sensor->pf();
|
||||
PZEM[5] = P102_PZEM_sensor->frequency();
|
||||
|
||||
for (uint8_t i = 0; i < 6; i++) // Check each PZEM field
|
||||
// Skip non-available values
|
||||
const uint8_t toCheckMax = PZEM_model::PZEM004Tv30 == static_cast<PZEM_model>(P102_PZEM_TYPE)
|
||||
? P102_PZEM004_VALUE_COUNT
|
||||
: P102_PZEM017_VALUE_COUNT;
|
||||
|
||||
for (uint8_t i = 0; i < toCheckMax; i++) // Check each PZEM field
|
||||
{
|
||||
if (PZEM[i] != PZEM[i]) // Check if NAN
|
||||
if (PZEM[i] != PZEM[i]) // Check if NAN
|
||||
{
|
||||
P102_PZEM_ATTEMPT == P102_PZEM_MAX_ATTEMPT ? P102_PZEM_ATTEMPT = 0 : P102_PZEM_ATTEMPT++;
|
||||
break; // if one is Not A Number, break
|
||||
break; // if one is Not A Number, break
|
||||
}
|
||||
P102_PZEM_ATTEMPT = 0;
|
||||
}
|
||||
@@ -333,10 +368,14 @@ boolean Plugin_102(uint8_t function, struct EventStruct *even
|
||||
# if FEATURE_PACKED_RAW_DATA
|
||||
case PLUGIN_GET_PACKED_RAW_DATA:
|
||||
{
|
||||
// Matching JS code:
|
||||
// Matching JS code for PZEM-004T:
|
||||
// return decode(bytes, [header, int16_1e1, int32_1e3, int32_1e1, int32_1e1, uint16_1e2, uint8_1e1],
|
||||
// ['header', 'voltage', 'current', 'power', 'energy', 'powerfactor', 'frequency']);
|
||||
//
|
||||
// Matching JS code for PZEM-017:
|
||||
// return decode(bytes, [header, int16_1e1, int32_1e3, int32_1e1, int32_1e1],
|
||||
// ['header', 'voltage', 'current', 'power', 'energy']);
|
||||
//
|
||||
// Resolutions:
|
||||
// Voltage: 0.1V => int16_1e1 (range 80-260V)
|
||||
// Current: 0.001A => int32_1e3
|
||||
@@ -347,13 +386,18 @@ boolean Plugin_102(uint8_t function, struct EventStruct *even
|
||||
|
||||
// FIXME TD-er: Calling these functions is probably done within the 200 msec timeout used in the library.
|
||||
// If not, this should be cached in a task data struct.
|
||||
string += LoRa_addFloat(P102_PZEM_sensor->voltage(), PackedData_int16_1e1);
|
||||
string += LoRa_addFloat(P102_PZEM_sensor->current(), PackedData_int32_1e3);
|
||||
string += LoRa_addFloat(P102_PZEM_sensor->power(), PackedData_int32_1e1);
|
||||
string += LoRa_addFloat(P102_PZEM_sensor->energy(), PackedData_int32_1e1);
|
||||
string += LoRa_addFloat(P102_PZEM_sensor->pf(), PackedData_uint16_1e2);
|
||||
string += LoRa_addFloat(P102_PZEM_sensor->frequency() - 40, PackedData_uint8_1e1);
|
||||
event->Par1 = 6; // valuecount
|
||||
string += LoRa_addFloat(P102_PZEM_sensor->voltage(), PackedData_int16_1e1);
|
||||
string += LoRa_addFloat(P102_PZEM_sensor->current(), PackedData_int32_1e3);
|
||||
string += LoRa_addFloat(P102_PZEM_sensor->power(), PackedData_int32_1e1);
|
||||
string += LoRa_addFloat(P102_PZEM_sensor->energy(), PackedData_int32_1e1);
|
||||
|
||||
if (PZEM_model::PZEM004Tv30 == static_cast<PZEM_model>(P102_PZEM_TYPE)) {
|
||||
string += LoRa_addFloat(P102_PZEM_sensor->pf(), PackedData_uint16_1e2);
|
||||
string += LoRa_addFloat(P102_PZEM_sensor->frequency() - 40, PackedData_uint8_1e1);
|
||||
event->Par1 = P102_PZEM004_VALUE_COUNT; // valuecount
|
||||
} else {
|
||||
event->Par1 = P102_PZEM017_VALUE_COUNT; // valuecount
|
||||
}
|
||||
|
||||
success = true;
|
||||
break;
|
||||
@@ -367,14 +411,10 @@ boolean Plugin_102(uint8_t function, struct EventStruct *even
|
||||
{
|
||||
const String command = parseString(string, 1);
|
||||
|
||||
if ((equals(command, F("resetenergy"))) && (P102_PZEM_FIRST == event->TaskIndex))
|
||||
{
|
||||
if ((event->Par1 >= 0) && (event->Par1 <= 247))
|
||||
{
|
||||
P102_PZEM_sensor->init(event->Par1);
|
||||
P102_PZEM_sensor->resetEnergy();
|
||||
success = true;
|
||||
}
|
||||
if (equals(command, F("resetenergy")) && (event->Par1 >= 0) && (event->Par1 <= 247)) {
|
||||
P102_PZEM_sensor->init(event->Par1);
|
||||
P102_PZEM_sensor->resetEnergy();
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -392,7 +432,7 @@ const __FlashStringHelper* p102_getQueryString(uint8_t query) {
|
||||
case 2: return F("Power_W");
|
||||
case 3: return F("Energy_kWh");
|
||||
case 4: return F("Power_Factor_cosphi");
|
||||
case 5: return F("Frequency Hz");
|
||||
case 5: return F("Frequency_Hz");
|
||||
}
|
||||
return F("");
|
||||
}
|
||||
|
||||
@@ -420,7 +420,7 @@ const char mqtt_binary_deviceclass_names[] PROGMEM =
|
||||
String MQTT_binary_deviceClassName(int devClassIndex) {
|
||||
char tmp[17]{}; // length: battery_charging + \0
|
||||
|
||||
String result(GetTextIndexed(tmp, sizeof(tmp), devClassIndex, mqtt_binary_deviceclass_names));
|
||||
const String result(GetTextIndexed(tmp, sizeof(tmp), devClassIndex, mqtt_binary_deviceclass_names));
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -429,7 +429,7 @@ int MQTT_binary_deviceClassIndex(const String& deviceClassName) {
|
||||
return GetCommandCode(deviceClassName.c_str(), mqtt_binary_deviceclass_names);
|
||||
}
|
||||
|
||||
// TwoWay devices are marked with ² in the selector, and disvocered as 'light' instead of 'binary_sensor'
|
||||
// TwoWay devices are marked with ² in the selector, and discovered as 'light' instead of 'binary_sensor'
|
||||
bool MQTT_binary_deviceClassTwoWay(int devClassIndex) {
|
||||
switch (devClassIndex) { // Index into mqtt_binary_deviceclass_names
|
||||
case 1: // power
|
||||
|
||||
@@ -828,7 +828,9 @@ void handle_devicess_ShowAllTasksTable(uint8_t page)
|
||||
html_TD();
|
||||
|
||||
if (validDeviceIndex(DeviceIndex)) {
|
||||
#if FEATURE_STRING_VARIABLES
|
||||
const DeviceStruct& device = Device[DeviceIndex];
|
||||
#endif // #if FEATURE_STRING_VARIABLES
|
||||
String customValuesString;
|
||||
const bool customValues = PluginCall(PLUGIN_WEBFORM_SHOW_VALUES, &TempEvent, customValuesString);
|
||||
|
||||
@@ -1083,7 +1085,7 @@ void handle_devices_TaskSettingsPage(taskIndex_t taskIndex, uint8_t page)
|
||||
addHtml(getPluginNameFromDeviceIndex(DeviceIndex));
|
||||
|
||||
const uint8_t pid = Settings.getPluginID_for_task(taskIndex).value;
|
||||
if (pid <= 101) { // Up to P101 seem to be listed in the old Wiki, so lets keep pointing there too
|
||||
if (pid <= 79) { // Up to P079 seem to be listed in the old Wiki (and a few incomplete pages), so lets keep pointing there too
|
||||
addHelpButton(concat(F("Plugin"), Settings.getPluginID_for_task(taskIndex).value));
|
||||
}
|
||||
addRTDPluginButton(Settings.getPluginID_for_task(taskIndex));
|
||||
|
||||
@@ -760,7 +760,7 @@ void handle_sysinfo_Storage() {
|
||||
|
||||
addRowLabel(LabelType::FLASH_WRITE_COUNT);
|
||||
addHtml(strformat(
|
||||
F("%d daily / %d boot"),
|
||||
F("%d daily / %d cold boot"),
|
||||
RTC.flashDayCounter,
|
||||
static_cast<int>(RTC.flashCounter)));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user