Skip to content

Instantly share code, notes, and snippets.

@felixstorm
Last active July 7, 2024 07:34
Show Gist options
  • Save felixstorm/18f8ad9fb31ca71bbf62ba32801c34ae to your computer and use it in GitHub Desktop.
Save felixstorm/18f8ad9fb31ca71bbf62ba32801c34ae to your computer and use it in GitHub Desktop.
WiCAN ESPHome Configuration (work in progress, abbreviated)
# Be warned: This is just a first try and still very much work in progress - no guarantees given whatsoever!
#
# To install the ESPHome firmware on the WiCAN for the first time (before being able to use ESPHome OTA), I built the firmware
# for download (in "modern" format) and then used the following command line on Linux:
# esptool.py --before=default_reset --after=hard_reset --no-stub write_flash --flash_mode dio --flash_freq 80m --flash_size 4MB 0x0 /home/.../Downloads/m-wican-factory.bin
#
# Don't forget to short the pins to enable boot mode (https://github.com/meatpiHQ/wican-fw#obd).
#
# Using the graphical tool (https://github.com/meatpiHQ/wican-fw#2-usb-flash) will probably work just as well. Just populate
# the first item in the list with 0x0 and /home/.../Downloads/m-wican-factory.bin and leave the rest empty.
#
# Thereafter I just used the ESPHome OTA feature - but be aware that WiFi must be turned on for this to work, i.e. the power
# safe mode (see below) must be off.
substitutions:
device_name: m-eup-wican
esp32:
variant: ESP32C3
board: esp32-c3-devkitm-1
esphome:
name: ${device_name}
logger:
api:
time:
platform: homeassistant
web_server:
version: 2
ota: false
include_internal: true
wifi:
# your details here
ota:
password: # your details here
packages:
leds:
output:
- id: blue_led_output
platform: gpio
pin: 7
- id: green_led_output
platform: gpio
pin: {number: 8, inverted: true}
- id: yellow_led_output
platform: gpio
pin: {number: 9, inverted: true}
light:
- platform: binary
id: blue_led
output: blue_led_output
- platform: binary
id: green_led
output: green_led_output
- platform: binary
id: yellow_led
output: yellow_led_output
can:
canbus:
- platform: esp32_can
tx_pin: 0
rx_pin: 3
bit_rate: 500kbps
can_id: 0 # mandatory but we do not use it
on_frame:
# dump all frames to log
- can_id: 0
can_id_mask: 0
then:
- lambda: |-
auto data_pretty = remote_transmission_request ? "n/a" : format_hex_pretty(x).c_str();
ESP_LOGD("eup_dump", "can_id: 0x%08x, rtr: %d, length: %d, content: %s", can_id, remote_transmission_request, x.size(), data_pretty);
# first byte: real data length
- can_id: 0x7ED # VWUP_BAT_MGMT_RX
then:
- lambda: |-
// VW e-Up absolute SOC from Battery Management (available during "vehicle on" and "vehicle charging")
if (x.size() >= 5 && x[0] >= 4 && x[1] == 98 && x[2] == 0x02 && x[3] == 0x8C) // VWUP_BAT_MGMT_SOC_ABS
// https://github.com/openvehicles/Open-Vehicle-Monitoring-System-3/blob/9ddbb0182158d8d7d4afe03dce61afb2ec856787/vehicle/OVMS.V3/components/vehicle_vweup/src/vweup_obd.cpp#L850
id(car_soc).publish_state(round(2.0f * x[4] * 100 / 250) / 2.0f); // round to 0.5 %
switch:
- platform: gpio
id: can_enabled
pin:
number: 6
inverted: true
restore_mode: ALWAYS_ON
# TBD: disabling CAN seems to disturb the driver badly and it will not work again after enabling again but only after reboot
# on_turn_on:
# - lambda: twai_start();
# on_turn_off:
# - lambda: twai_stop(); # keep driver error counter low
script:
# Poll PIDs
# first byte: data length
# second byte 0x22: VEHICLE_POLL_TYPE_READDATA / ReadDataByIdentifier (16 bit PID)
# needs to be filled up with 0xAA to be accepted by the control units
- id: query_soc_script
then:
- if:
condition: {switch.is_on: can_enabled}
then:
# VW e-Up SOC from Battery Management (available during "vehicle on" and "vehicle charging")
# based on https://github.com/openvehicles/Open-Vehicle-Monitoring-System-3/blob/9ddbb0182158d8d7d4afe03dce61afb2ec856787/vehicle/OVMS.V3/components/vehicle_vweup/src/vweup_obd.cpp#L67
# also see "xvu.b.soc" here: https://docs.openvehicles.com/en/latest/components/vehicle_vweup/docs/index_obd.html#custom-metrics
- canbus.send:
can_id: 0x7E5 # VWUP_BAT_MGMT_TX
data: [ 3, 0x22, 0x02, 0x8C, 0xAA, 0xAA, 0xAA, 0xAA ] # VWUP_BAT_MGMT_SOC_ABS
interval:
- interval: 1min
then:
- script.execute: query_soc_script
sensor:
- platform: template
id: car_soc
name: '${device_name} car_soc'
unit_of_measurement: '%'
accuracy_decimals: 1
device_class: battery
state_class: measurement
power_safe_mode:
sensor:
- platform: adc
id: starter_battery_voltage
name: '${device_name} starter_battery_voltage'
pin: 4
attenuation: 11db # https://github.com/meatpiHQ/wican-fw/blob/bf212132f8e506f2c520e917daf86e53a1070302/main/sleep_mode.c#L234
filters:
- lambda: return x * 116 / 16; # https://github.com/meatpiHQ/wican-fw/blob/bf212132f8e506f2c520e917daf86e53a1070302/main/sleep_mode.c#L397
update_interval: 5s
unit_of_measurement: V
accuracy_decimals: 1
device_class: voltage
state_class: measurement
binary_sensor:
- platform: template
id: car_is_on
name: '${device_name} car_is_on'
lambda: return id(starter_battery_voltage).state >= 12.9;
# did not find any other way to realize different timeouts for on and off :-(
# neither delay_on and delay_off nor on_state with delays based on state did work reliably
on_state:
- script.execute: power_safe_mode_script
script:
- id: power_safe_mode_script
mode: restart # important, otherwise delays will not cancel each other
then:
- if:
condition: {binary_sensor.is_on: car_is_on}
then:
- delay: 10sec
- switch.turn_off: power_safe_mode
else:
- delay: 3min
- switch.turn_on: power_safe_mode
switch:
- platform: template
id: power_safe_mode
name: '${device_name} power_safe_mode'
optimistic: true
restore_mode: ALWAYS_OFF
on_turn_on:
- logger.log: "Power Safe Mode: ON"
- delay: 3sec # allow to send the latest state to HA before disconnecting wifi
# - switch.turn_off: can_enabled
- wifi.disable:
on_turn_off:
- logger.log: "Power Safe Mode: OFF"
- wifi.enable:
# - switch.turn_on: can_enabled
- delay: 10sec
- script.execute: query_soc_script
api:
# Required for wifi.disable to not trigger a reboot. We probably need to keep an eye on this to ensure that it really
# is not required. A potential workaround could be to just trigger a reboot when resuming from power safe mode.
# This would also have the advantage of not having to disable and again re-enable the CAN bus for sleeping.
reboot_timeout: 0s
@felixstorm
Copy link
Author

@jaripetteri I added some comments in the gist above and switched some values to hex - this way it should be more obvious where the constants etc. come from.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment