Thank you! I assume only 2 of the 4 channels are required right? Just considering getting something smaller
I updated mine to use external component. Create the folders and files under esphome
__init__.py
# just required so Python treats the folder as a package
sensor.py
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor
from esphome.const import (
UNIT_WATT, ICON_FLASH, DEVICE_CLASS_POWER,
UNIT_VOLT, DEVICE_CLASS_VOLTAGE,
UNIT_AMPERE, DEVICE_CLASS_CURRENT,
)
wion_ns = cg.esphome_ns.namespace("wion_power_monitor")
WionPowerMonitor = wion_ns.class_("WionPowerMonitor", cg.PollingComponent)
CONFIG_SCHEMA = cv.Schema({
cv.GenerateID(): cv.declare_id(WionPowerMonitor),
cv.Optional("power"): sensor.sensor_schema(
unit_of_measurement=UNIT_WATT,
icon=ICON_FLASH,
accuracy_decimals=1,
device_class=DEVICE_CLASS_POWER,
),
cv.Optional("voltage"): sensor.sensor_schema(
unit_of_measurement=UNIT_VOLT,
accuracy_decimals=1,
device_class=DEVICE_CLASS_VOLTAGE,
),
cv.Optional("current"): sensor.sensor_schema(
unit_of_measurement=UNIT_AMPERE,
accuracy_decimals=1,
device_class=DEVICE_CLASS_CURRENT,
),
cv.Optional("power_factor"): sensor.sensor_schema(
accuracy_decimals=1,
),
})
async def to_code(config):
var = cg.new_Pvariable(config[cv.CONF_ID])
await cg.register_component(var, config)
if "power" in config:
sens = await sensor.new_sensor(config["power"])
cg.add(var.set_power_sensor(sens))
if "voltage" in config:
sens = await sensor.new_sensor(config["voltage"])
cg.add(var.set_voltage_sensor(sens))
if "current" in config:
sens = await sensor.new_sensor(config["current"])
cg.add(var.set_current_sensor(sens))
if "power_factor" in config:
sens = await sensor.new_sensor(config["power_factor"])
cg.add(var.set_powerf_sensor(sens))
wion_power_monitor.cpp
#include "wion_power_monitor.h"
#include "esphome/core/log.h"
namespace esphome {
namespace wion_power_monitor {
void WionPowerMonitor::setup() {
pinMode(0, OUTPUT);
pinMode(12, INPUT);
digitalWrite(0, HIGH);
}
void WionPowerMonitor::update() {
const int numBlocks = 4;
const int bitsPerBlock = 32;
int data[numBlocks];
for (int block = 0; block < numBlocks; block++) {
for (int bitIdx = bitsPerBlock - 1; bitIdx >= 0; bitIdx--) {
digitalWrite(0, LOW);
delayMicroseconds(35);
bitWrite(data[block], bitIdx, digitalRead(12));
digitalWrite(0, HIGH);
delayMicroseconds(35);
}
}
for (int block = 0; block < numBlocks; block++) {
for (int bit = 24; bit < 32; bit++) {
bitWrite(data[block], bit, 0);
}
}
ESP_LOGD(TAG, "raw: %#08X; %#08X; %#08X; %#08X", data[0], data[1], data[2], data[3]);
float power = data[0];
float voltage = data[1];
float powerF = data[2];
float current = data[3];
power = power / 3; // calibrated against Sonoff S31
if (power < 1 || power > 2000) {
power = 0;
}
if (data[0] != 0xFFFFFF && current < 3000) {
if (power_sensor) power_sensor->publish_state(power);
if (voltage_sensor) voltage_sensor->publish_state(voltage);
if (powerf_sensor) powerf_sensor->publish_state(powerF);
if (current_sensor) current_sensor->publish_state(current);
}
}
void WionPowerMonitor::dump_config() {
ESP_LOGCONFIG(TAG, "Wion Power Monitor:");
LOG_SENSOR(" ", "Power", this->power_sensor);
LOG_SENSOR(" ", "Voltage", this->voltage_sensor);
LOG_SENSOR(" ", "PowerF", this->powerf_sensor);
LOG_SENSOR(" ", "Current", this->current_sensor);
}
} // namespace wion_power_monitor
} // namespace esphome
wion_power_monitor.h
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
namespace esphome {
namespace wion_power_monitor {
static const char *const TAG = "wion_power_monitor";
class WionPowerMonitor : public PollingComponent {
public:
WionPowerMonitor() : PollingComponent(15000) {}
// setters called from sensor.py
void set_power_sensor(sensor::Sensor *s) { power_sensor = s; }
void set_voltage_sensor(sensor::Sensor *s) { voltage_sensor = s; }
void set_current_sensor(sensor::Sensor *s) { current_sensor = s; }
void set_powerf_sensor(sensor::Sensor *s) { powerf_sensor = s; }
float get_setup_priority() const override { return esphome::setup_priority::BUS; }
void setup() override;
void update() override;
void dump_config() override;
protected:
sensor::Sensor *power_sensor{nullptr};
sensor::Sensor *voltage_sensor{nullptr};
sensor::Sensor *current_sensor{nullptr};
sensor::Sensor *powerf_sensor{nullptr};
};
} // namespace wion_power_monitor
} // namespace esphome
esphome YAML
esphome:
name: "wion-plug"
friendly_name: WION-Plug
esp8266:
board: esp01_1m
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "key"
ota:
- platform: esphome
password: "password"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Wion-Plug Fallback Hotspot"
password: "password"
switch:
- platform: gpio
name: " Plug"
pin: GPIO15
id: relay1
binary_sensor:
- platform: gpio
pin:
number: GPIO13
id: button
on_press:
- switch.toggle: relay1
- platform: status
name: Plug
light:
- platform: binary
name: "LED"
output: light_output
restore_mode: ALWAYS_OFF
output:
- id: light_output
platform: gpio
pin: GPIO14
- id: wifi_output
platform: gpio
pin: GPIO2
inverted: true
interval:
- interval: 5s
then:
if:
condition:
wifi.connected:
then:
- output.turn_on: wifi_output
else:
- output.turn_off: wifi_output
external_components:
- source:
type: local
path: ./external_components
sensor:
- platform: wion_power_monitor
power:
name: "Power"
captive_portal:
I am only using the power sensor, but the rest are in the code
hi, I did a complete reverse engineering of this plug, I posted the code here GitHub - Taxom/WiOn-50055-ESPHome: ESPHome replacement firmware for the Woods WiOn 50055 Wi-Fi outlet, retaining the stock power-monitoring hardware. · GitHub


