Merge pull request #4225 from tonhuisman/feature/P138-add-ip5306-power-management-plugin

[P138] Add Power mgt - IP5306 plugin
This commit is contained in:
TD-er
2023-01-26 22:16:08 +01:00
committed by GitHub
21 changed files with 1059 additions and 1 deletions
+120
View File
@@ -0,0 +1,120 @@
.. include:: ../Plugin/_plugin_substitutions_p13x.repl
.. _P138_page:
|P138_typename|
==================================================
|P138_shortinfo|
Plugin details
--------------
Type: |P138_type|
Name: |P138_name|
Status: |P138_status|
GitHub: |P138_github|_
Maintainer: |P138_maintainer|
Used libraries: |P138_usedlibraries|
Description
-----------
I2C Power management controller. As found in some ESP32 models of M5Stack and TTGO.
Plugin is only available in ESP32 builds, as this controller is currently only found to be used with ESP32 boards. It can be used on ESP8266, though untested.
Configuration
--------------
.. image:: P138_DeviceConfiguration.png
:alt: Device configuration
* **Name** A unique name should be entered here.
* **Enabled** The device can be disabled or enabled. When not enabled the device should not use any resources.
I2C Options
^^^^^^^^^^^^
The available settings here depend on the build used. At least the **Force Slow I2C speed** option is available, but selections for the I2C Multiplexer can also be shown. For details see the :ref:`Hardware_page`
Device Settings
^^^^^^^^^^^^^^^^
* **Decimals for config values**: The number of decimals to use for presenting the Config values (see below for a list of available values).
* **Event on PowerSource change**: When checked the plugin will generate an event ``<taskname>#PowerChanged`` with argument 0 or 1 for battery or external power (the new state).
Output Configuration
^^^^^^^^^^^^^^^^^^^^
* **Number Output Values**: Select the number of values that have to be available. The default is set to *Quad*, as there are far more than 4 values available for display.
.. image:: P138_NumberOutputValuesOptions.png
Available options: *Single* (1), *Dual* (2), *Triple* (3) and *Quad* (4).
* **Value 1..4**: Select the desired value to be available in the Values fields. The name of the Values will be set to a matching default automatically, but can be changed afterward.
.. image:: P138_ValueOptions.png
Available options:
* *None*: To leave the value empty/0.00
* *Battery current*: The current measured at the Battery connection.
* *Charge undervoltage*: The (fixed) voltage at which charging of the battery is started by the controller.
* *Stop voltage*: The (fixed) configured voltage at which the battery is no longer being charged.
* *Input current*: The input current used by the controller.
* *Charge level*: The charge level of the battery.
* *Power source*: The power source used by the ESP, 0 = battery, 1 = External (USB) power.
Data Acquisition
^^^^^^^^^^^^^^^^
This group of settings, **Single event with all values**, **Send to Controller** and **Interval** settings are standard available configuration items. Send to Controller is only visible when one or more Controllers are configured.
**Interval** By default, Interval will be set to 0 sec. as it is optional. When set > 0 it is the frequency used to read sensor values and send these to any Controllers configured for this device.
Values
^^^^^^
The measured values are available in variables, where the names are determined by the selected **Value 1..4** settings. A formula can be set to recalculate. The number of decimals can be set as desired, and defaults to 2.
.. Commands
.. ~~~~~~~~
.. .. include:: P138_commands.repl
Extra values
~~~~~~~~~~~~
As this plugin has more values available than can be set to the regular Values outputs, all values are also available from the Get Config feature.
.. include:: P138_values.repl
Extra events
~~~~~~~~~~~~
Besides the regular events, of ``<taskname>#<valuename>=<value>`` or ``<taskname>#All=<value1>,..<valueN>`` when the **Interval** is set, there can be an extra event generated:
.. include:: P138_events.repl
Change log
----------
.. versionchanged:: 2.0
|added| 2022-08-26 Initially added.
Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

+12
View File
@@ -0,0 +1,12 @@
.. csv-table::
:header: "Event", "Extra information"
:widths: 20, 30
"
| ``<taskname>#PowerChanged=<source>``
| ``source``: ``0`` (Battery power) or ``1`` (External / USB power).
","
| Event generated when the **Event on PowerSource change** is enabled.
"
+34
View File
@@ -0,0 +1,34 @@
.. csv-table::
:escape: ^
:widths: 20, 30
"
``[<taskname>#batterycurrent]``
","
The current measured at the Battery connection.
"
"
``[<taskname>#chargeundervoltage]``
","
The (fixed) voltage at which charging of the battery is started by the controller.
"
"
``[<taskname>#stopvoltage]``
","
The (fixed) configured voltage at which the battery is no longer being charged.
"
"
``[<taskname>#inputcurrent]``
","
The input current used by the controller.
"
"
``[<taskname>#chargelevel]``
","
The charge level of the battery.
"
"
``[<taskname>#powersource]``
","
The power source used by the ESP, 0 = battery, 1 = External (USB) power.
"
+6
View File
@@ -362,6 +362,7 @@ There are different released versions of ESP Easy:
":ref:`P133_page`","|P133_status|","P133"
":ref:`P134_page`","|P134_status|","P134"
":ref:`P135_page`","|P135_status|","P135"
":ref:`P138_page`","|P138_status|","P138"
":ref:`P141_page`","|P141_status|","P141"
":ref:`P143_page`","|P143_status|","P143"
":ref:`P148_page`","|P148_status|","P148"
@@ -511,6 +512,11 @@ Plugins: |Plugin_Position|
Hardware: |P013_usedby|, |P082_usedby|
Power management
----------------
Plugins: |Plugin_PowerMgt|
Regulator
---------
@@ -23,6 +23,7 @@
.. |Plugin_Notify| replace:: :ref:`P055_page`, :ref:`P065_page`
.. |Plugin_Output| replace:: :ref:`P029_page`, :ref:`P038_page`, :ref:`P041_page`, :ref:`P042_page`, :ref:`P043_page`, :ref:`P070_page`, :ref:`P124_page`, :ref:`P126_page`, :ref:`P128_page`
.. |Plugin_Position| replace:: :ref:`P013_page`, :ref:`P082_page`, :ref:`P121_page`
.. |Plugin_PowerMgt| replace:: :ref:`P138_page`
.. |Plugin_Regulator| replace:: :ref:`P021_page`
.. |Plugin_RFID| replace:: :ref:`P008_page`, :ref:`P017_page`, :ref:`P040_page`, :ref:`P111_page`
.. |Plugin_Switch_input| replace:: :ref:`P001_page`, :ref:`P009_page`, :ref:`P019_page`, :ref:`P059_page`, :ref:`P080_page`, :ref:`P091_page`, :ref:`P097_page`, :ref:`P143_page`
@@ -62,3 +62,16 @@
.. |P135_maintainer| replace:: `tonhuisman`
.. |P135_compileinfo| replace:: `.`
.. |P135_usedlibraries| replace:: `https://github.com/sparkfun/SparkFun_SCD4x_Arduino_Library`
.. |P138_name| replace:: :cyan:`IP5306 Power management`
.. |P138_type| replace:: :cyan:`Power mgt`
.. |P138_typename| replace:: :cyan:`Power mgt - IP5306 Power management`
.. |P138_porttype| replace:: `.`
.. |P138_status| replace:: :yellow:`COLLECTION` :yellow:`DISPLAY` :yellow:`ENERGY` :yellow:`NEOPIXEL`
.. |P138_github| replace:: P138_IP5306.ino
.. _P138_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P138_IP5306.ino
.. |P138_usedby| replace:: `.`
.. |P138_shortinfo| replace:: `Power management controller`
.. |P138_maintainer| replace:: `tonhuisman`
.. |P138_compileinfo| replace:: `.`
.. |P138_usedlibraries| replace:: `https://github.com/codewitch-honey-crisis/htcw_ip5306`
+4
View File
@@ -528,6 +528,10 @@ P129 :ref:`P129_page`
.. include:: ../Plugin/P129_events.repl
P138 :ref:`P138_page`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. include:: ../Plugin/P138_events.repl
P143 :ref:`P143_page`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 honey the codewitch
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+13
View File
@@ -0,0 +1,13 @@
# button
This library allows you to use the IP5306 power management module
```
[env:node32s]
platform = espressif32
board = node32s
framework = arduino
lib_deps =
codewitch-honey-crisis/htcw_ip5306@^0.1.0
lib_ldf_mode = deep
```
+108
View File
@@ -0,0 +1,108 @@
#pragma once
#include <Arduino.h>
#include <Wire.h>
namespace arduino {
enum struct ip5306_shutdown {
after_8s=0,
after_32s=1,
after_16s=2,
after_64s=3
};
enum struct ip5306_charging_full_voltage {
at_4_14v=0,
at_4_17v=1,
at_4_185v=2,
at_4_2v=3,
};
enum struct ip5306_press_time {
press_2_seconds=0,
press_3_seconds=1
};
enum struct ip5306_end_charge_current {
at_200mA = 0,
at_400mA = 1,
at_500mA = 2,
at_600mA = 3
};
enum struct ip5306_voltage_pressure {
none = 0,
p_14mV=1,
p_28mV=2,
p_42mV=3
};
enum struct ip5306_charge_cutoff_voltage {
at_4_2v = 0,
at_4_3v = 1,
at_4_35v = 2,
at_4_4v = 3
};
enum struct ip5306_source {
battery = 0,
vin = 1
};
enum struct ip5306_load {
heavy = 0,
light = 1
};
enum struct ip5306_presses {
short_press_twice = 0,
long_press_once = 1
};
class ip5306 {
TwoWire& m_i2c;
public:
constexpr static const uint8_t address = 0x75;
inline ip5306(TwoWire& i2c=Wire) : m_i2c(i2c) {
}
bool key_off() const;
void key_off(bool value);
bool boost_output() const;
void boost_output(bool value);
bool power_on_load() const;
void power_on_load(bool value);
bool charger() const;
void charger(bool value);
bool boost() const;
void boost(bool value);
bool low_battery_shutdown() const;
void low_battery_shutdown(bool value);
bool boost_after_vin() const;
void boost_after_vin(bool value);
bool short_press_boot_switch() const;
void short_press_boot_switch(bool value);
ip5306_presses flashlight_clicks() const;
void flashlight_clicks(ip5306_presses value);
ip5306_presses boost_off_clicks() const;
void boost_off_clicks(ip5306_presses value);
ip5306_shutdown light_load_shutdown_time() const;
void light_load_shutdown_time(ip5306_shutdown value);
ip5306_press_time long_press_time() const;
void long_press_time(ip5306_press_time value);
ip5306_charging_full_voltage charging_full_stop_voltage() const;
void charging_full_stop_voltage(ip5306_charging_full_voltage value);
float charge_under_voltage_loop() const;
void charge_under_voltage_loop(float value);
ip5306_end_charge_current end_charge_current_detection() const;
void end_charge_current_detection(ip5306_end_charge_current value);
ip5306_voltage_pressure voltage_pressure() const;
void voltage_pressure(ip5306_voltage_pressure value);
ip5306_charge_cutoff_voltage charge_cutoff_voltage() const;
void charge_cutoff_voltage(ip5306_charge_cutoff_voltage value);
ip5306_source charge_cc_loop() const;
void charge_cc_loop(ip5306_source value);
unsigned vin_current() const;
void vin_current(unsigned value);
bool short_press_detected() const;
void clear_short_press_detected();
bool long_press_detected() const;
void clear_long_press_detected();
bool double_click_detected() const;
void clear_double_click_detected();
ip5306_source power_source() const;
bool battery_full() const;
ip5306_load output_load() const;
float charge_level() const;
};
}
+18
View File
@@ -0,0 +1,18 @@
{
"name": "htcw_ip5306",
"version": "0.1.0",
"description": "Provides support for the IP5306 power module",
"keywords": ["power", "battery", "sleep"],
"authors": {
"name":"honey the codewitch",
"homepage": "https://www.codeproject.com/Members/code-witch"
},
"license": "MIT",
"frameworks": ["arduino"],
"platforms": "*",
"repository":
{
"type": "git",
"url": "https://github.com/codewitch-honey-crisis/htcw_ip5306.git"
}
}
+250
View File
@@ -0,0 +1,250 @@
#include <ip5306.hpp>
namespace arduino {
// based on
// https://gist.github.com/me-no-dev/7702f08dd578de5efa47caf322250b57
/*
** IP5306 Power Module
*/
/* M5 Defaults
KeyOff: Enabled
BoostOutput: Disabled
PowerOnLoad: Enabled
Charger: Enabled
Boost: Enabled
LowBatShutdown: Enabled
ShortPressBoostSwitch: Disabled
FlashlightClicks: Double Press
BoostOffClicks: Long Press
BoostAfterVin: Open
LongPressTime: 2s
ChargeUnderVoltageLoop: 4.55V
ChargeCCLoop: Vin
VinCurrent: 2250mA
VoltagePressure: 28mV
ChargingFullStopVoltage: 4.17V
LightLoadShutdownTime: 32s
EndChargeCurrentDetection: 500mA
ChargeCutoffVoltage: 4.2V
*/
#define IP5306_REG_SYS_0 0x00
#define IP5306_REG_SYS_1 0x01
#define IP5306_REG_SYS_2 0x02
#define IP5306_REG_CHG_0 0x20
#define IP5306_REG_CHG_1 0x21
#define IP5306_REG_CHG_2 0x22
#define IP5306_REG_CHG_3 0x23
#define IP5306_REG_CHG_4 0x24
#define IP5306_REG_READ_0 0x70
#define IP5306_REG_READ_1 0x71
#define IP5306_REG_READ_2 0x72
#define IP5306_REG_READ_3 0x77
#define IP5306_REG_READ_4 0x78
#define IP5306_LEDS2PCT(byte) \
((byte & 0x01 ? 25 : 0) + \
(byte & 0x02 ? 25 : 0) + \
(byte & 0x04 ? 25 : 0) + \
(byte & 0x08 ? 25 : 0))
int ip5306_get_reg(TwoWire& i2c, uint8_t reg){
i2c.beginTransmission(ip5306::address);
i2c.write(reg);
if(i2c.endTransmission(false) == 0 && i2c.requestFrom(0x75, 1)){
return i2c.read();
}
return -1;
}
int ip5306_set_reg(TwoWire& i2c, uint8_t reg, uint8_t value){
i2c.beginTransmission(ip5306::address);
i2c.write(reg);
i2c.write(value);
if(i2c.endTransmission(true) == 0){
return 0;
}
return -1;
}
uint8_t ip5306_get_bits(TwoWire& i2c, uint8_t reg, uint8_t index, uint8_t bits){
int value = ip5306_get_reg(i2c,reg);
if(value < 0){
Serial.printf("ip5306_get_bits fail: 0x%02x\n", reg);
return 0;
}
return (value >> index) & ((1 << bits)-1);
}
void ip5306_set_bits(TwoWire& i2c, uint8_t reg, uint8_t index, uint8_t bits, uint8_t value){
uint8_t mask = (1 << bits) - 1;
int v = ip5306_get_reg(i2c,reg);
if(v < 0){
Serial.printf("ip5306_get_reg fail: 0x%02x\n", reg);
return;
}
v &= ~(mask << index);
v |= ((value & mask) << index);
if(ip5306_set_reg(i2c,reg, v)){
Serial.printf("ip5306_set_bits fail: 0x%02x\n", reg);
}
}
bool ip5306::key_off() const {
return ip5306_get_bits(m_i2c,IP5306_REG_SYS_0, 0, 1);
}
void ip5306::key_off(bool value) {
ip5306_set_bits(m_i2c,IP5306_REG_SYS_0, 0, 1, value);
}
bool ip5306::boost_output() const {
return ip5306_get_bits(m_i2c,IP5306_REG_SYS_0, 1, 1);
}
void ip5306::boost_output(bool value) {
ip5306_set_bits(m_i2c,IP5306_REG_SYS_0, 1, 1, value);
}
bool ip5306::power_on_load() const {
return ip5306_get_bits(m_i2c,IP5306_REG_SYS_0, 2, 1);
}
void ip5306::power_on_load(bool value) {
ip5306_set_bits(m_i2c,IP5306_REG_SYS_0, 2, 1, value);
}
bool ip5306::charger() const {
return ip5306_get_bits(m_i2c,IP5306_REG_SYS_0, 4, 1);
}
void ip5306::charger(bool value) {
ip5306_set_bits(m_i2c,IP5306_REG_SYS_0, 4, 1, value);
}
bool ip5306::boost() const {
return ip5306_get_bits(m_i2c,IP5306_REG_SYS_0, 5, 1);
}
void ip5306::boost(bool value) {
ip5306_set_bits(m_i2c,IP5306_REG_SYS_0, 5, 1, value);
}
bool ip5306::low_battery_shutdown() const {
return ip5306_get_bits(m_i2c,IP5306_REG_SYS_1, 0, 1);
}
void ip5306::low_battery_shutdown(bool value) {
ip5306_set_bits(m_i2c,IP5306_REG_SYS_1, 0, 1, value);
}
bool ip5306::boost_after_vin() const {
return ip5306_get_bits(m_i2c,IP5306_REG_SYS_1, 2, 1);
}
void ip5306::boost_after_vin(bool value) {
ip5306_set_bits(m_i2c,IP5306_REG_SYS_1, 2, 1, value);
}
bool ip5306::short_press_boot_switch() const {
return ip5306_get_bits(m_i2c,IP5306_REG_SYS_1, 5, 1);
}
void ip5306::short_press_boot_switch(bool value) {
return ip5306_set_bits(m_i2c,IP5306_REG_SYS_1, 5, 1, value);
}
ip5306_presses ip5306::flashlight_clicks() const {
return (ip5306_presses)ip5306_get_bits(m_i2c,IP5306_REG_SYS_1, 6, 1);
}
void ip5306::flashlight_clicks(ip5306_presses value) {
ip5306_set_bits(m_i2c,IP5306_REG_SYS_1, 6, 1, (int)value);
}
ip5306_presses ip5306::boost_off_clicks() const {
return (ip5306_presses)(1-ip5306_get_bits(m_i2c,IP5306_REG_SYS_1, 7, 1));
}
void ip5306::boost_off_clicks(ip5306_presses value) {
ip5306_set_bits(m_i2c,IP5306_REG_SYS_1, 7, 1, 1-((int)value));
}
ip5306_shutdown ip5306::light_load_shutdown_time() const {
return (ip5306_shutdown)ip5306_get_bits(m_i2c,IP5306_REG_SYS_2, 2, 2);
}
void ip5306::light_load_shutdown_time(ip5306_shutdown value) {
ip5306_set_bits(m_i2c,IP5306_REG_SYS_2, 2, 2, (int)value);
}
ip5306_press_time ip5306::long_press_time() const {
return (ip5306_press_time)ip5306_get_bits(m_i2c,IP5306_REG_SYS_2, 4, 1);
}
void ip5306::long_press_time(ip5306_press_time value) {
ip5306_set_bits(m_i2c,IP5306_REG_SYS_2, 4, 1, (int)value);
}
ip5306_charging_full_voltage ip5306::charging_full_stop_voltage() const {
return (ip5306_charging_full_voltage)ip5306_get_bits(m_i2c,IP5306_REG_CHG_0, 0, 2);
}
void ip5306::charging_full_stop_voltage(ip5306_charging_full_voltage value) {
ip5306_set_bits(m_i2c,IP5306_REG_CHG_0, 0, 2, (int)value);
}
float ip5306::charge_under_voltage_loop() const {
//Automatically adjust the charging current when the voltage of VOUT is greater than the set value
//Vout=4.45V + (v * 0.05V) (default 4.55V)
//When charging at the maximum current, the charge is less than the set value. Slowly reducing the charging current to maintain this voltage
int v = ip5306_get_bits(m_i2c,IP5306_REG_CHG_1, 2, 3);
return 4.45+(v*.05);
}
void ip5306::charge_under_voltage_loop(float value) {
value-=4.45;
int i = value/.05;
ip5306_set_bits(m_i2c,IP5306_REG_CHG_1, 2, 3, i);
}
ip5306_end_charge_current ip5306::end_charge_current_detection() const {
return (ip5306_end_charge_current)ip5306_get_bits(m_i2c,IP5306_REG_CHG_1, 6, 2);
}
void ip5306::end_charge_current_detection(ip5306_end_charge_current value) {
ip5306_set_bits(m_i2c,IP5306_REG_CHG_1, 6, 2, (int)value);
}
ip5306_voltage_pressure ip5306::voltage_pressure() const {
return (ip5306_voltage_pressure)ip5306_get_bits(m_i2c,IP5306_REG_CHG_2, 0, 2);
}
void ip5306::voltage_pressure(ip5306_voltage_pressure value) {
ip5306_set_bits(m_i2c,IP5306_REG_CHG_2, 0, 2, (int)value);
}
ip5306_charge_cutoff_voltage ip5306::charge_cutoff_voltage() const {
return (ip5306_charge_cutoff_voltage)ip5306_get_bits(m_i2c,IP5306_REG_CHG_2, 2, 2);
}
void ip5306::charge_cutoff_voltage(ip5306_charge_cutoff_voltage value) {
ip5306_set_bits(m_i2c,IP5306_REG_CHG_2, 2, 2, (int)value);
}
ip5306_source ip5306::charge_cc_loop() const {
return (ip5306_source)ip5306_get_bits(m_i2c,IP5306_REG_CHG_3, 5, 1);
}
void ip5306::charge_cc_loop(ip5306_source value) {
ip5306_set_bits(m_i2c,IP5306_REG_CHG_3, 5, 1, (int)value);
}
unsigned ip5306::vin_current() const {
int v = ip5306_get_bits(m_i2c,IP5306_REG_CHG_4, 0, 5);
return (v*100)+50;
}
void ip5306::vin_current(unsigned value) {
//ImA=(v*100)+50 (default 2250mA)
ip5306_set_bits(m_i2c,IP5306_REG_CHG_4, 0, 5, (value-50)/100);
}
bool ip5306::short_press_detected() const {
return ip5306_get_bits(m_i2c,IP5306_REG_READ_3, 0, 1);
}
void ip5306::clear_short_press_detected() {
ip5306_set_bits(m_i2c,IP5306_REG_READ_3, 0, 1, 1);
}
bool ip5306::long_press_detected() const {
return ip5306_get_bits(m_i2c,IP5306_REG_READ_3, 1, 1);
}
void ip5306::clear_long_press_detected() {
ip5306_set_bits(m_i2c,IP5306_REG_READ_3, 1, 1, 1);
}
bool ip5306::double_click_detected() const {
return ip5306_get_bits(m_i2c,IP5306_REG_READ_3, 2, 1);
}
void ip5306::clear_double_click_detected() {
ip5306_set_bits(m_i2c,IP5306_REG_READ_3, 2, 1, 1);
}
ip5306_source ip5306::power_source() const {
return (ip5306_source)ip5306_get_bits(m_i2c,IP5306_REG_READ_0, 3, 1);
}
bool ip5306::battery_full() const {
return ip5306_get_bits(m_i2c,IP5306_REG_READ_1, 3, 1);
}
ip5306_load ip5306::output_load() const {
return (ip5306_load)ip5306_get_bits(m_i2c,IP5306_REG_READ_2, 2, 1);
}
float ip5306::charge_level() const {
// LED[0-4] State (inverted)
return IP5306_LEDS2PCT(((~ip5306_get_bits(m_i2c,IP5306_REG_READ_4, 4, 4)) & 0x0F))/100.0;
}
}
+1
View File
@@ -474,6 +474,7 @@ static const char DATA_ESPEASY_DEFAULT_MIN_CSS[] PROGMEM = {
// #define USES_P134 // A02YYUW
// #define USES_P135 // SCD4x
// #define P135_FEATURE_RESET_COMMANDS 1 // Enable/Disable quite spacious (~950 bytes) 'selftest' and 'factoryreset' subcommands
// #define USES_P138 // IP5306
// #define USES_P141 // PCD8544 Nokia 5110 LCD
// #define USES_P143 // I2C Rotary encoders
// #define P143_FEATURE_INCLUDE_M5STACK 0 // Enabled by default, can be turned off here
+234
View File
@@ -0,0 +1,234 @@
#include "_Plugin_Helper.h"
#ifdef USES_P138
// #######################################################################################################
// #################################### Plugin 138: IP5306 Powermanagement ###############################
// #######################################################################################################
/**
* Changelog:
* 2022-12-06 tonhuisman: Reorder Device configuration because of added PLUGIN_WEBFORM_LOAD_OUTPUT_SELECTOR state
* Enable PluginStats option
* 2022-12-05 tonhuisman: Remove [Testing] tag
* 2022-11-08 tonhuisman: Fix a few typos, cleanup some comments
* 2022-08-26 tonhuisman: Initial plugin development, using codewitch-honey-crisis/htcw_ip5306 library
**/
/**
* Supported commands: (none yet)
**/
/**
* Get Config options:
* [<taskname>#batcurrent] : Battery current
* [<taskname>#chundervolt] : Charge Undervoltage
* [<taskname>#stopvolt] : Input voltage
* [<taskname>#inpcurrent] : Input current
* [<taskname>#pwrsource] : Powersource
* // To re-use these lines:
* [<taskname>#vbuscurr] : VBus current
* [<taskname>#inttemp] : Internal temperature
* [<taskname>#apsvolt] : APS voltage
* [<taskname>#ldo2volt] : LDO2 voltage
* [<taskname>#ldo3volt] : LDO3 voltage
* [<taskname>#gpio0volt] : GPIO0 voltage
**/
# define PLUGIN_138
# define PLUGIN_ID_138 138
# define PLUGIN_NAME_138 "Power mgt - IP5306 Power management"
# include "./src/PluginStructs/P138_data_struct.h"
boolean Plugin_138(uint8_t function, struct EventStruct *event, String& string)
{
boolean success = false;
switch (function)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_138;
Device[deviceCount].Type = DEVICE_TYPE_I2C;
Device[deviceCount].VType = Sensor_VType::SENSOR_TYPE_QUAD;
Device[deviceCount].OutputDataType = Output_Data_type_t::Simple;
Device[deviceCount].FormulaOption = true;
Device[deviceCount].ValueCount = 4;
Device[deviceCount].SendDataOption = true;
Device[deviceCount].TimerOption = true;
Device[deviceCount].TimerOptional = true;
Device[deviceCount].PluginStats = true;
break;
}
case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_138);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
for (uint8_t i = 0; i < VARS_PER_TASK; ++i) {
if (i < P138_NR_OUTPUT_VALUES) {
safe_strncpy(
ExtraTaskSettings.TaskDeviceValueNames[i],
toString(static_cast<P138_valueOptions_e>(PCONFIG(P138_CONFIG_BASE + i)), false),
sizeof(ExtraTaskSettings.TaskDeviceValueNames[i]));
} else {
ZERO_FILL(ExtraTaskSettings.TaskDeviceValueNames[i]);
}
}
break;
}
case PLUGIN_GET_DEVICEVALUECOUNT:
{
event->Par1 = P138_NR_OUTPUT_VALUES;
success = true;
break;
}
case PLUGIN_GET_DEVICEVTYPE:
{
event->sensorType = static_cast<Sensor_VType>(PCONFIG(P138_SENSOR_TYPE_INDEX));
event->idx = P138_SENSOR_TYPE_INDEX;
success = true;
break;
}
case PLUGIN_I2C_HAS_ADDRESS:
{
success = event->Par1 == 0x75;
break;
}
case PLUGIN_SET_DEFAULTS:
{
PCONFIG(0) = static_cast<int>(P138_valueOptions_e::StopVoltage);
PCONFIG(1) = static_cast<int>(P138_valueOptions_e::InCurrent);
PCONFIG(2) = static_cast<int>(P138_valueOptions_e::BatteryCurrent);
PCONFIG(3) = static_cast<int>(P138_valueOptions_e::ChargeLevel);
PCONFIG(P138_SENSOR_TYPE_INDEX) = static_cast<uint8_t>(Sensor_VType::SENSOR_TYPE_QUAD);
P138_CONFIG_DECIMALS = 2; // 2 decimals for all get config values
bitSet(P138_CONFIG_FLAGS, P138_FLAG_POWERCHANGE); // Enable event
break;
}
case PLUGIN_WEBFORM_LOAD_OUTPUT_SELECTOR:
{
{
const __FlashStringHelper *valOptions[] = {
toString(P138_valueOptions_e::None),
toString(P138_valueOptions_e::BatteryCurrent),
toString(P138_valueOptions_e::ChargeUnderVoltage),
toString(P138_valueOptions_e::StopVoltage),
toString(P138_valueOptions_e::InCurrent),
toString(P138_valueOptions_e::ChargeLevel),
toString(P138_valueOptions_e::PowerSource),
};
const int valValues[] = {
static_cast<int>(P138_valueOptions_e::None),
static_cast<int>(P138_valueOptions_e::BatteryCurrent),
static_cast<int>(P138_valueOptions_e::ChargeUnderVoltage),
static_cast<int>(P138_valueOptions_e::StopVoltage),
static_cast<int>(P138_valueOptions_e::InCurrent),
static_cast<int>(P138_valueOptions_e::ChargeLevel),
static_cast<int>(P138_valueOptions_e::PowerSource),
};
for (uint8_t i = 0; i < P138_NR_OUTPUT_VALUES; i++) {
sensorTypeHelper_loadOutputSelector(event,
P138_CONFIG_BASE + i,
i,
sizeof(valValues) / sizeof(int),
valOptions,
valValues);
}
}
success = true;
break;
}
case PLUGIN_WEBFORM_LOAD:
{
addFormNumericBox(F("Decimals for config values"), F("decimals"), P138_CONFIG_DECIMALS, 0, 4);
addFormCheckBox(F("Event on PowerSource change"), F("eventpwrchg"), bitRead(P138_CONFIG_FLAGS, P138_FLAG_POWERCHANGE));
success = true;
break;
}
case PLUGIN_WEBFORM_SAVE:
{
for (uint8_t i = 0; i < P138_NR_OUTPUT_VALUES; i++) {
sensorTypeHelper_saveOutputSelector(event, P138_CONFIG_BASE + i, i,
toString(static_cast<P138_valueOptions_e>(PCONFIG(P138_CONFIG_BASE + i)), false));
}
P138_CONFIG_DECIMALS = getFormItemInt(F("decimals"));
bitWrite(P138_CONFIG_FLAGS, P138_FLAG_POWERCHANGE, isFormItemChecked(F("eventpwrchg")));
success = true;
break;
}
case PLUGIN_INIT:
{
initPluginTaskData(event->TaskIndex, new (std::nothrow) P138_data_struct(event));
P138_data_struct *P138_data = static_cast<P138_data_struct *>(getPluginTaskData(event->TaskIndex));
if (nullptr != P138_data) {
success = true;
}
break;
}
case PLUGIN_READ:
{
P138_data_struct *P138_data = static_cast<P138_data_struct *>(getPluginTaskData(event->TaskIndex));
if (nullptr != P138_data) {
success = P138_data->plugin_read(event);
}
break;
}
case PLUGIN_FIFTY_PER_SECOND:
{
P138_data_struct *P138_data = static_cast<P138_data_struct *>(getPluginTaskData(event->TaskIndex));
if (nullptr != P138_data) {
success = P138_data->plugin_fifty_per_second(event);
}
break;
}
// case PLUGIN_WRITE:
// {
// P138_data_struct *P138_data = static_cast<P138_data_struct *>(getPluginTaskData(event->TaskIndex));
// if (nullptr != P138_data) {
// success = P138_data->plugin_write(event, string);
// }
// break;
// }
case PLUGIN_GET_CONFIG_VALUE:
{
P138_data_struct *P138_data = static_cast<P138_data_struct *>(getPluginTaskData(event->TaskIndex));
if (nullptr != P138_data) {
success = P138_data->plugin_get_config_value(event, string); // GetConfig operation, handle variables
}
break;
}
}
return success;
}
#endif // USES_P138
+12
View File
@@ -1405,6 +1405,9 @@ To create/register a plugin, you have to :
#define USES_P081 // Cron
#define USES_P082 // GPS
#define USES_P089 // Ping
#if !defined(USES_P138) && defined(ESP32)
#define USES_P138 // IP5306
#endif
#endif
#ifdef PLUGIN_SET_COLLECTION_A
@@ -1538,6 +1541,9 @@ To create/register a plugin, you have to :
#ifndef USES_P132
#define USES_P132 // INA3221
#endif
#if !defined(USES_P138) && defined(ESP32)
#define USES_P138 // IP5306
#endif
#ifndef USES_P148
#define USES_P148 // Sonoff POWR3xxD and THR3xxD display
#endif
@@ -1603,6 +1609,9 @@ To create/register a plugin, you have to :
#ifndef USES_P116
#define USES_P116 // ST77xx
#endif
#if !defined(USES_P138) && defined(ESP32)
#define USES_P138 // IP5306
#endif
#ifndef USES_P141
#define USES_P141 // PCD8544 Nokia 5110
#endif
@@ -1762,6 +1771,9 @@ To create/register a plugin, you have to :
#ifdef ESP8266
#define FEATURE_CHART_JS 0
#endif
#if !defined(USES_P138) && defined(ESP32)
#define USES_P138 // IP5306
#endif
#endif
#ifdef CONTROLLER_SET_COLLECTION
+150
View File
@@ -0,0 +1,150 @@
#include "../PluginStructs/P138_data_struct.h"
#ifdef USES_P138
// **************************************************************************/
// toString: convert P138_valueOptions_e enum to value-name or display-name
// **************************************************************************/
const __FlashStringHelper* toString(const P138_valueOptions_e value, bool displayString) {
switch (value) {
case P138_valueOptions_e::None: return displayString ? F("None") : F("none");
case P138_valueOptions_e::BatteryCurrent: return displayString ? F("Battery current") : F("batterycurrent");
case P138_valueOptions_e::ChargeUnderVoltage: return displayString ? F("Charge undervoltage") : F("chargeundervoltage");
case P138_valueOptions_e::StopVoltage: return displayString ? F("Stop voltage") : F("stopvoltage");
case P138_valueOptions_e::InCurrent: return displayString ? F("Input current") : F("inputcurrent");
case P138_valueOptions_e::ChargeLevel: return displayString ? F("Charge level") : F("chargelevel");
case P138_valueOptions_e::PowerSource: return displayString ? F("Power source") : F("powersource");
}
return F("*Undefined*");
}
// **************************************************************************/
// Constructor
// **************************************************************************/
P138_data_struct::P138_data_struct(struct EventStruct *event) {
addLog(LOG_LEVEL_INFO, F("IP5306: Init."));
_ip5306 = new (std::nothrow) arduino::ip5306(); // Default address and I2C Wire object
}
// **************************************************************************/
// Destructor
// **************************************************************************/
P138_data_struct::~P138_data_struct() {
delete _ip5306;
_ip5306 = nullptr;
}
// **************************************************************************/
// plugin_read: Read the values and send to controller(s)
// **************************************************************************/
bool P138_data_struct::plugin_read(struct EventStruct *event) {
bool success = true;
for (uint8_t i = 0; i < P138_NR_OUTPUT_VALUES; i++) {
UserVar[event->BaseVarIndex + i] = read_value(static_cast<P138_valueOptions_e>(PCONFIG(P138_CONFIG_BASE + i)));
}
return success;
}
// **************************************************************************/
// plugin_fifty_per_second: check if the powersource changed and generate an event for that
// **************************************************************************/
bool P138_data_struct::plugin_fifty_per_second(struct EventStruct *event) {
bool success = true;
if (bitRead(P138_CONFIG_FLAGS, P138_FLAG_POWERCHANGE) && isInitialized()) {
int8_t src = static_cast<int8_t>(_ip5306->power_source());
if (_lastPowerSource != src) { // Changed?
String eventCommand = getTaskDeviceName(event->TaskIndex);
eventCommand += F("#PowerChanged=");
eventCommand += src; // 0 = battery, 1 = Vin
eventQueue.add(eventCommand);
_lastPowerSource = src; // Keep current
}
}
return success;
}
// **************************************************************************/
// read_value: Read the requested value
// **************************************************************************/
float P138_data_struct::read_value(P138_valueOptions_e value) {
if (isInitialized()) {
switch (value) {
case P138_valueOptions_e::None: return 0.0f;
case P138_valueOptions_e::BatteryCurrent: {
const float charge_current[] = { 200.0f, 400.0f, 500.0f, 600.0f };
return charge_current[static_cast<int>(_ip5306->end_charge_current_detection())];
}
case P138_valueOptions_e::ChargeUnderVoltage: return _ip5306->charge_under_voltage_loop();
case P138_valueOptions_e::StopVoltage: {
const float stop_voltage[] = { 4.14f, 4.17f, 4.185f, 4.2f };
return stop_voltage[static_cast<int>(_ip5306->charging_full_stop_voltage())];
}
case P138_valueOptions_e::InCurrent: return static_cast<float>(_ip5306->vin_current());
case P138_valueOptions_e::ChargeLevel: return _ip5306->charge_level() * 100.0f; // Make percentage
case P138_valueOptions_e::PowerSource: return static_cast<float>(_ip5306->power_source()); // 0 = batt, 1 = Vin
}
}
return 0.0f;
}
// **************************************************************************/
// plugin_write: Process commands
// **************************************************************************/
bool P138_data_struct::plugin_write(struct EventStruct *event,
const String & string) {
bool success = false;
// String cmd = parseString(string, 1);
// if (isInitialized() && cmd.equals(F("ip5306"))) { // Command trigger
// cmd = parseString(string, 2); // sub command
// const bool empty3 = parseString(string, 3).isEmpty();
// const bool empty4 = parseString(string, 4).isEmpty();
// success = true;
// if (cmd.equals(F("??")) && !empty3) { // ip5306,??,<value>
// } else {
// success = false;
// }
// }
return success;
}
/****************************************************************************
* plugin_get_config_value: Retrieve values like [<taskname>#<valuename>]
***************************************************************************/
bool P138_data_struct::plugin_get_config_value(struct EventStruct *event,
String & string) {
bool success = true;
String command = parseString(string, 1);
float value;
if (command.equals(F("batcurrent"))) { // batcurrent
value = read_value(P138_valueOptions_e::BatteryCurrent);
} else if (command.equals(F("chundervolt"))) { // chundervolt
value = read_value(P138_valueOptions_e::ChargeUnderVoltage);
} else if (command.equals(F("stopvolt"))) { // stopvolt
value = read_value(P138_valueOptions_e::StopVoltage);
} else if (command.equals(F("inpcurrent"))) { // inpcurrent
value = read_value(P138_valueOptions_e::InCurrent);
} else if (command.equals(F("chargelvl"))) { // chargelvl
value = read_value(P138_valueOptions_e::ChargeLevel);
} else if (command.equals(F("pwrsource"))) { // pwrsource
value = read_value(P138_valueOptions_e::PowerSource);
} else {
success = false;
}
if (success) {
string = toString(value, static_cast<unsigned int>(P138_CONFIG_DECIMALS));
}
return success;
}
#endif // ifdef USES_P138
+59
View File
@@ -0,0 +1,59 @@
#ifndef PLUGINSTRUCTS_P138_DATA_STRUCT_H
#define PLUGINSTRUCTS_P138_DATA_STRUCT_H
#include "../../_Plugin_Helper.h"
#ifdef USES_P138
# include <ip5306.hpp>
# define P138_DEBUG_LOG // Enable for some (extra) logging
# define P138_CONFIG_BASE 0 // Uses PCONFIG(0)..PCONFIG(3) to store the selection for 4 output values
# define P138_SENSOR_TYPE_INDEX (P138_CONFIG_BASE + VARS_PER_TASK)
# define P138_NR_OUTPUT_VALUES getValueCountFromSensorType(static_cast<Sensor_VType>(PCONFIG(P138_SENSOR_TYPE_INDEX)))
# define P138_CONFIG_DECIMALS PCONFIG(P138_CONFIG_BASE + VARS_PER_TASK + 1)
# define P138_CONFIG_FLAGS PCONFIG_ULONG(0)
# define P138_FLAG_POWERCHANGE 0 // Flag 0: Send event on PowerChange event
enum class P138_valueOptions_e : uint8_t {
None = 0x00,
BatteryCurrent = 0x01,
ChargeUnderVoltage = 0x02,
StopVoltage = 0x03,
InCurrent = 0x04,
ChargeLevel = 0x05,
PowerSource = 0x06,
};
const __FlashStringHelper* toString(const P138_valueOptions_e value,
bool displayString = true);
struct P138_data_struct : public PluginTaskData_base {
public:
P138_data_struct(struct EventStruct *event);
P138_data_struct() = delete;
~P138_data_struct();
bool plugin_read(struct EventStruct *event);
bool plugin_fifty_per_second(struct EventStruct *event);
bool plugin_write(struct EventStruct *event,
const String & string);
bool plugin_get_config_value(struct EventStruct *event,
String & string);
private:
arduino::ip5306 *_ip5306 = nullptr;
bool isInitialized() {
return nullptr != _ip5306;
}
float read_value(P138_valueOptions_e value);
int8_t _lastPowerSource = -1;
};
#endif // ifdef USES_P138
#endif // ifndef PLUGINSTRUCTS_P138_DATA_STRUCT_H
+3 -1
View File
@@ -327,9 +327,11 @@ String getKnownI2Cdevice(uint8_t address) {
result += F("HT16K33,TCA9543a/6a/8a I2C multiplexer");
break;
case 0x74:
case 0x75:
result += F("HT16K33,TCA9546a/8a I2C multiplexer");
break;
case 0x75:
result += F("HT16K33,TCA9546a/8a I2C multiplexer,IP5306");
break;
case 0x76:
result += F("BMP280,BME280,BME680,MS5607,MS5611,HT16K33,TCA9546a/8a I2C multiplexer");
break;