substitutions:
  device_name: "meanwell-can-esp32"
  name: "MeanWell CAN ESP32"

esphome:
  name: ${device_name}
  friendly_name: ${name}
  comment: ${name}

esp32:
  board: esp32doit-devkit-v1

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_pass
  fast_connect: true

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: ${name}

captive_portal:

# Enable logging
logger:

# Enable Home Assistant API
api:

ota:

web_server:
  port: 80

button:
  - platform: restart
    name: Reboot
  - platform: template
    id: bit7_disable
    name: Switch to PSU mode
    on_press:
      - canbus.send:
          canbus_id: can_mcp2515
          data: [0xB4, 0x00, 0x04, 0x00]
      - lambda: |-
          ESP_LOGD("main", "CAN set CURVE_CONFIG (0x00B4) Bit 7 = 0 (0x0004), please power cycle NPB afterwards", ""); 
  - platform: template
    id: bit7_enable
    name: Switch to Charger mode
    on_press:
      - canbus.send:
          canbus_id: can_mcp2515
          data: [0xB4, 0x00, 0x84, 0x00]
      - lambda: |-
          ESP_LOGD("main", "CAN set CURVE_CONFIG (0x00B4) Bit 7 = 1 (0x0084), please power cycle NPB afterwards", ""); 
  - platform: template
    id: get_system_status
    name: Get system status
    on_press:
      - canbus.send:
          canbus_id: can_mcp2515
          data: [0xC1, 0x00]
      - lambda: |-
          ESP_LOGD("main", "CAN get SYSTEM_STATUS (0x00C1)", ""); 
  # - platform: template
  #   id: get_serial_number
  #   name: Get serial number
  #   on_press:
  #     - canbus.send:
  #         canbus_id: can_mcp2515
  #         data: [0x88, 0x00]
  #     - lambda: |-
  #         ESP_LOGD("main", "CAN get MFR_SERIAL_B6B11 (0x0088)", ""); 
  - platform: template
    id: get_curve_config
    name: Get curve config
    on_press:
      - canbus.send:
          canbus_id: can_mcp2515
          data: [0xB4, 0x00]
      - lambda: |-
          ESP_LOGD("main", "CAN get CURVE_CONFIG (0x00B4)", ""); 
  - platform: template
    id: get_operation_status
    name: Get operation status
    on_press:
      - canbus.send:
          canbus_id: can_mcp2515
          data: [0x00, 0x00]
      - lambda: |-
          ESP_LOGD("main", "CAN get OPERATION (0x0000)", ""); 
  - platform: template
    id: read_current
    name: Read charging current
    on_press:
      - canbus.send:
          canbus_id: can_mcp2515
          data: [0x61, 0x00]
      - lambda: |-
          ESP_LOGD("main", "CAN get READ_IOUT (0x0061)", ""); 
  - platform: template
    id: read_voltage
    name: Read charging voltage
    on_press:
      - canbus.send:
          canbus_id: can_mcp2515
          data: [0x60, 0x00]
      - lambda: |-
          ESP_LOGD("main", "CAN get READ_VOUT (0x0060)", ""); 
  - platform: template
    id: read_temperature
    name: Read temperature
    on_press:
      - canbus.send:
          canbus_id: can_mcp2515
          data: [0x62, 0x00]
      - lambda: |-
          ESP_LOGD("main", "CAN get READ_TEMPERATURE_1 (0x0062)", ""); 
  - platform: template
    id: enable_charging
    name: Enable charging
    on_press:
      - canbus.send:
          canbus_id: can_mcp2515
          data: [0x00, 0x00, 0x01]
      - lambda: |-
          ESP_LOGD("main", "CAN set OPERATION (0x0000), enable charging (0x01)", ""); 
      - delay:
          milliseconds: 100
      - button.press: set_current
  - platform: template
    id: disable_charging
    name: Disable charging
    on_press:
      - canbus.send:
          canbus_id: can_mcp2515
          data: [0x00, 0x00, 0x00]
      - lambda: |-
          ESP_LOGD("main", "CAN set OPERATION (0x0000), disable charging (0x00)", ""); 
      - delay:
          milliseconds: 100
  - platform: template
    id: set_current
    name: Set charging current
    on_press:
      then:
        if:
          condition:
            lambda: |-
              return (id(target_current).state);
          then:
            - lambda: |-
                uint32_t can_id = 0x00C0103;
                bool use_extended_id = 1;
                float x = float(id(target_current).state);
                uint16_t current = x*100;
                ESP_LOGD("main", "Target current is %f, must become %d then %02x", x, current, current);
                uint8_t hex1 = current >> 8;
                uint8_t hex0 = current | hex1;
                std::vector<uint8_t> data{0x30, 0x00, hex1, hex0};
                ESP_LOGD("main", "CAN set IOUT_SET (0x0030) to %f (%02x %02x)", x, hex1, hex0);
                float curr = float(float((int((hex0) + ((hex1) << 8)))) / 100);
                ESP_LOGD("main", "Charging current set to %f Amps", curr);
                id(can_mcp2515)->send_data(can_id, use_extended_id, data);
            - delay:
                milliseconds: 100
          else:
            - lambda: |-
                ESP_LOGD("main", "Target current is invalid, skip", "");

switch:
  - platform: template
    id: sw_read_periodically_enable
    name: Read charging data periodically
    optimistic: yes
    assumed_state: false
    restore_mode: RESTORE_DEFAULT_OFF
  - platform: template
    id: sw_charging
    name: Charging
    optimistic: yes
    assumed_state: false
    turn_on_action:
      - button.press: enable_charging
    turn_off_action:
      - button.press: disable_charging

text_sensor:
  - platform: template
    id: ts_serial_number
    name: Serial number
  - platform: template
    id: ts_system_status
    name: System status
  - platform: template
    id: ts_curve_config
    name: Curve config

binary_sensor:
  - platform: template
    id: bs_operation_status
    name: Operation status (charging)

sensor:
  - platform: template
    id: se_charging_current
    name: Charging current
    unit_of_measurement: A
    device_class: current
    state_class: measurement
    accuracy_decimals: 2
  - platform: template
    id: se_charging_voltage
    name: Charging voltage
    unit_of_measurement: V
    device_class: voltage
    state_class: measurement
    accuracy_decimals: 2
  - platform: template
    id: se_temperature
    name: Internal temperature
    unit_of_measurement: °C
    device_class: temperature
    state_class: measurement
    accuracy_decimals: 1

number:
  - platform: template
    optimistic: yes
    max_value: 22.5
    min_value: 4.5
    step: 0.1
    id: target_current
    name: Target charging current
    set_action:
      - delay:
          milliseconds: 100
      - button.press: set_current

spi:
  id: mcp2515_spi
  clk_pin: GPIO18
  mosi_pin: GPIO23
  miso_pin: GPIO19
time:
  - platform: homeassistant
    on_time:
      seconds: 6/20
      then:
        - button.press: get_system_status
        - delay:
            milliseconds: 100
#        - button.press: get_serial_number
#        - delay:
#            milliseconds: 100
        - button.press: get_operation_status
        - delay:
            milliseconds: 100
        - button.press: read_temperature
        - delay:
            milliseconds: 100
        - if:
            condition:
              and:
                - switch.is_on: sw_charging
                - binary_sensor.is_off: bs_operation_status
            then:
              button.press: enable_charging
        - if:
            condition:
              and:
                - switch.is_off: sw_charging
                - binary_sensor.is_on: bs_operation_status
            then:
              button.press: disable_charging
  - platform: homeassistant
    on_time: 
      seconds: /10
      then: 
        - if:
            condition:
              switch.is_on: sw_read_periodically_enable
            then:
              - button.press: read_current
              - delay:
                  milliseconds: 100
              - button.press: read_voltage
              - delay:
                  milliseconds: 100

canbus:
  - platform: mcp2515
    id: can_mcp2515
    spi_id: mcp2515_spi
    cs_pin: GPIO5
    can_id: 0x000C0103
    use_extended_id: true
    clock: 8MHZ
    bit_rate: 250KBPS 
    on_frame: 
    - can_id: 0x000C0003
#      can_id_mask: 0x1fffff00
      use_extended_id: true
      then: 
#      - lambda: |-
#           ESP_LOGD("WOW", "Got x[0]: %02x", x[0]);
#           ESP_LOGD("WOW", "Got x[1]: %02x", x[1]);
      - lambda: |-
          if(x[0] == 0x00 and x[1] == 0x00) {
            int x2 = int(x[2]);
            id(bs_operation_status).publish_state(x2 == 1);
            ESP_LOGD("main", "Got OPERATION: %02x", x2);
          }
      - lambda: |-
          if(x[0] == 0x30 and x[1] == 0x00) {
            float current = float(float((int(x[2] + (x[3] << 8)))) / 100);
            id(se_charging_current).publish_state(current);
            ESP_LOGD("main", "Got IOUT_SET: %f", current);
          }
      - lambda: |-
          if(x[0] == 0x60 and x[1] == 0x00) {
            float voltage = float(float((int(x[2] + (x[3] << 8)))) / 100);
            id(se_charging_voltage).publish_state(voltage);
            ESP_LOGD("main", "Got READ_VOUT: %f", voltage);
          }
      - lambda: |-
          if(x[0] == 0x61 and x[1] == 0x00) {
            float current = float(float((int(x[2] + (x[3] << 8)))) / 100);
            id(se_charging_current).publish_state(current);
            ESP_LOGD("main", "Got READ_IOUT: %f", current);
          }
      - lambda: |-
          if(x[0] == 0x62 and x[1] == 0x00) {
            float temperature = float(float((int(x[2] + (x[3] << 8)))) / 10);
            id(se_temperature).publish_state(temperature);
            ESP_LOGD("main", "Got READ_TEMPERATURE_1: %f", temperature);
          }
      - lambda: |-
          if(x[0] == 0x88 and x[1] == 0x00) {
            int x2 = int(x[2]);
            int x3 = int(x[3] << 8);   
            int serial_number = int(x2 & x3);
            id(ts_serial_number).publish_state(to_string(serial_number));
            ESP_LOGD("main", "Got MFR_SERIAL_B6B11: %f (Hex: %02x %02x)", serial_number, x[2], x[3]);
          }
      - lambda: |-
          if(x[0] == 0xB4 and x[1] == 0x00) {
            int x2 = int(x[2]);
            int x3 = int(x[3]);
            int curve_config = int(x[2] + (x[3] << 8));
            id(ts_curve_config).publish_state(to_string(curve_config));
            ESP_LOGD("main", "Got CURVE_CONFIG: %f (Hex: %02x %02x)", curve_config, x[2], x[3]);
          }
      - lambda: |-
          if(x[0] == 0xC1 and x[1] == 0x00) {
            int status = int(x[2] + (x[3] << 8));
            id(ts_system_status).publish_state(to_string(status));
            ESP_LOGD("main", "Got SYSTEM_SATUS: %i (Hex: %02x %02x)", status, x[2], x[3]);
          }