ESPhome configuration
substitutions:
# Change this model to fit your particular one.
# You can find it in Home Assistant as the device diagnostic "Model Name".
model: "XY6014"
device_name: "xy6014-controller"
device_friendly_name: "sinilink-XY6014"
device_description: "Power Supply"
# Model specific settings (Don't change these!)
XY6014_voltage_maximum: "60"
XY6014_voltage_accuracy: "2"
XY6014_voltage_multiplier: "0.01"
XY6014_current_maximum: "14"
XY6014_current_accuracy: "3"
XY6014_current_multiplier: "0.01"
globals:
- id: vin_undervoltage_theshold
type: float
restore_value: no
initial_value: '17'
esphome:
name: $device_name
friendly_name: $device_friendly_name
comment: $device_description
name_add_mac_suffix: false
project:
name: "sinilink.xy5008-controller"
version: "1.0.0"
esp8266:
board: d1_mini
# Enable logging
logger:
level: INFO
# Disable logging via UART, since we're using this for modbus communication
baud_rate: 0
# Enable status LED
status_led:
pin:
number: GPIO2
inverted: true
web_server:
port: 80
local: true
log: false
# Enable Home Assistant API
api:
# encryption:
# key: !secret home_assistant_key
reboot_timeout: 0s
ota:
- platform: esphome
#password: !secret ota_password
# Configure WiFi
wifi:
networks:
- ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "XY6014 Fallback Hotspot"
password: ""
text_sensor:
- platform: wifi_info
ip_address:
name: ESP IP Address
id: ip_address
on_value:
then:
- lambda: |-
- platform: template
name: "Turn On Time"
lambda: |-
char buffer[16];
std::string ton_time;
std::snprintf(buffer, 16, "%02d:%02d:%02d" , (int)id(turnon_hours).state, (int)id(turnon_minutes).state, (int)id(turnon_seconds).state);
ton_time = buffer;
return {ton_time};
update_interval: 1s
interval:
- interval: 5s
then:
- lambda: |-
char ip[18];
char *ptr =ip;
strncpy(ip,id(ip_address).state.c_str(),17);
ip[17]=0;
int ip1 = atoi(ptr);
ptr = strchr( ptr, '.');
if (ptr!=NULL) {
int ip2 = atoi(++ptr);
ptr = strchr( ptr, '.');
if (ptr!=NULL) {
int ip3 = atoi(++ptr);
ptr = strchr( ptr, '.');
if (ptr!=NULL) {
int ip4 = atoi(++ptr);
esphome::modbus_controller::ModbusController *controller = id(powersupply);
// create the payload
std::vector wifi_data = { 0x3b3a, 2, 4, uint16_t((ip1 << 8) | ip2), uint16_t((ip3 << 8) | ip4) };
// Create a ModBUS command item with the wifi information as the payload
esphome::modbus_controller::ModbusCommandItem set_wifi_command =
esphome::modbus_controller::ModbusCommandItem::create_write_multiple_command(controller, 0x30, 5, wifi_data);
// Submit the command to the send queue
powersupply->queue_command(set_wifi_command);
}
}
}
- interval: 1s
then:
- lambda: |-
esphome::modbus_controller::ModbusController *controller = id(powersupply);
esphome::modbus_controller::ModbusCommandItem set_wifi_command =
esphome::modbus_controller::ModbusCommandItem::create_read_command(controller, esphome::modbus_controller::ModbusRegisterType::HOLDING, 0x30, 5);
// Submit the command to the send queue
powersupply->queue_command(set_wifi_command);
- interval: 0.5s
then:
- lambda: |-
static int count = 0;
static int delay_count = 0;
static int uv_count = 0;
if ((id(output_switch).state) && (id(cutoff_current).state!=0) && (id(output_current).state < id(cutoff_current).state)){
if (count>=5) {
count = 0;
id(output_switch).turn_off();
id(out_relay).turn_off();
}
else count++;
}
else count=0;
if (id(input_voltage).state < id(vin_undervoltage_theshold)) { if (uv_count<4) uv_count++; }
else {
if (id(output_switch).state) id(out_relay).turn_on();
uv_count=0;
}
if (uv_count >=4) {
id(out_relay).turn_off();
}
if (id(out_relay).state) {
if (id(output_switch).state) delay_count=0;
else delay_count++;
}
else delay_count=0;
if (delay_count>=120*3) {
id(out_relay).turn_off();
delay_count=0;
}
captive_portal:
uart:
id: mod_bus
tx_pin: GPIO1
rx_pin: GPIO3
baud_rate: 115200
data_bits: 8
stop_bits: 1
parity: none
modbus:
id: modbus1
# send_wait_time: 1ms
modbus_controller:
- id: powersupply
## This address should be set to the "Address" value in the config menu
address: 0x01
modbus_id: modbus1
setup_priority: 600
update_interval: 1s
command_throttle: 1ms
time:
- platform: homeassistant
id: ha_time
sensor:
- platform: modbus_controller
modbus_controller_id: powersupply
address: 2
name: "Output voltage"
id: output_voltage
device_class: voltage
state_class: measurement
unit_of_measurement: "V"
register_type: holding
value_type: U_WORD
accuracy_decimals: ${${model}_voltage_accuracy}
filters:
- multiply: ${${model}_voltage_multiplier}
- platform: modbus_controller
modbus_controller_id: powersupply
address: 3
name: "Output current"
id: output_current
device_class: current
state_class: measurement
unit_of_measurement: "A"
register_type: holding
value_type: U_WORD
accuracy_decimals: ${${model}_current_accuracy}
filters:
- multiply: ${${model}_current_multiplier}
- platform: modbus_controller
modbus_controller_id: powersupply
address: 4
name: "Output Power"
device_class: power
state_class: measurement
unit_of_measurement: "W"
register_type: holding
value_type: U_WORD
accuracy_decimals: 2
filters:
- multiply: 0.1
- platform: modbus_controller
modbus_controller_id: powersupply
address: 5
name: "Input voltage"
id: input_voltage
device_class: voltage
unit_of_measurement: "V"
register_type: holding
value_type: U_WORD
accuracy_decimals: ${${model}_voltage_accuracy}
#accuracy_decimals: 3
filters:
# - multiply: ${${model}_voltage_multiplier}
- multiply: 0.01
- platform: modbus_controller
modbus_controller_id: powersupply
address: 6
name: "Battery charge"
device_class: "energy_storage"
state_class: measurement
unit_of_measurement: "Ah"
icon: "mdi:battery-60"
register_type: holding
value_type: U_DWORD_R
accuracy_decimals: 3
filters:
- multiply: 0.001
- platform: modbus_controller
modbus_controller_id: powersupply
address: 8
name: "Battery energy"
device_class: "energy_storage"
state_class: measurement
unit_of_measurement: "Wh"
icon: "mdi:battery-60"
register_type: holding
value_type: U_DWORD_R
accuracy_decimals: 3
filters:
- multiply: 0.001
- platform: modbus_controller
modbus_controller_id: powersupply
address: 10
name: "turnon_hours"
id: turnon_hours
unit_of_measurement: "hours"
register_type: holding
value_type: U_WORD
internal: true
- platform: modbus_controller
modbus_controller_id: powersupply
address: 11
name: "turnon_minutes"
id: turnon_minutes
unit_of_measurement: "minutes"
register_type: holding
value_type: U_WORD
internal: true
- platform: modbus_controller
modbus_controller_id: powersupply
address: 12
name: "turnon_seconds"
id: turnon_seconds
unit_of_measurement: "seconds"
register_type: holding
value_type: U_WORD
internal: true
- platform: modbus_controller
name: "Temperature"
device_class: temperature
state_class: measurement
modbus_controller_id: powersupply
register_type: holding
address: 13
value_type: S_WORD
unit_of_measurement: "°C"
accuracy_decimals: 1
filters:
- multiply: 0.1
- platform: modbus_controller
name: "Temperature external"
state_class: measurement
modbus_controller_id: powersupply
register_type: holding
address: 14
value_type: S_WORD
device_class: temperature
unit_of_measurement: "°C"
accuracy_decimals: 1
filters:
- multiply: 0.1
- platform: modbus_controller
name: "Host type"
state_class: measurement
modbus_controller_id: powersupply
register_type: holding
address: 48
value_type: U_WORD
internal: true
- platform: template
name: "Battery Charge Power"
id: battery_power
unit_of_measurement: "W"
device_class: "power"
state_class: "measurement"
accuracy_decimals: 1
lambda: |-
if (id(output_current).state > 0.05) {
return id(output_voltage).state * id(output_current).state;
} else {
return 0.0;
}
- platform: total_daily_energy
name: "Battery Charge Today"
power_id: battery_power
unit_of_measurement: "Wh"
device_class: "energy"
state_class: "total_increasing"
accuracy_decimals: 0
restore: false
binary_sensor:
- platform: modbus_controller
modbus_controller_id: powersupply
name: "Constant Voltage"
address: 17
register_type: holding
bitmask: 0x1
filters:
- invert:
- platform: modbus_controller
modbus_controller_id: powersupply
name: "Constant Current"
address: 17
register_type: holding
bitmask: 0x1
number:
- platform: modbus_controller
modbus_controller_id: powersupply
name: "Set output voltage"
device_class: voltage
unit_of_measurement: "V"
entity_category: config
mode: box
address: 0
value_type: U_WORD
min_value: 0
max_value: ${${model}_voltage_maximum}
step: ${${model}_voltage_multiplier}
lambda: !lambda return x * ${${model}_voltage_multiplier};
write_lambda: !lambda return x * (1/${${model}_voltage_multiplier});
- platform: modbus_controller
modbus_controller_id: powersupply
name: "Set output current"
device_class: current
unit_of_measurement: "A"
entity_category: config
mode: box
address: 1
value_type: U_WORD
min_value: 0
max_value: ${${model}_current_maximum}
step: ${${model}_current_multiplier}
lambda: !lambda return x * ${${model}_current_multiplier};
write_lambda: !lambda return x * (1/${${model}_current_multiplier});
- platform: template
name: "Under current cutoff (battery charge)"
id: cutoff_current
device_class: current
unit_of_measurement: "A"
entity_category: config
mode: box
min_value: 0
max_value: ${${model}_current_maximum}
step: ${${model}_current_multiplier}
optimistic: true
switch:
- platform: modbus_controller
modbus_controller_id: powersupply
name: "Output"
id: output_switch
address: 18
register_type: holding
bitmask: 0x1
entity_category: config
- platform: gpio
id: out_relay
name: "Output relay"
pin:
number: GPIO4
inverted: falseFlash
esphome run sinilink-modbus.yaml --device /dev/ttyUSB0