Newer
Older
homeassistant_config / esphome / nilan300.yaml
esphome:
  name: nilan300

esp32:
  board: nodemcu-32s
  framework:
    type: esp-idf

# Enable logging
logger:
  level: DEBUG
  baud_rate: 0

# Enable Home Assistant API
api:

ota:
  platform: esphome
  password: "9939debfff235f69eb37720d836f209c"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  
uart:
  rx_pin: GPIO16
  tx_pin: GPIO17
  parity: EVEN
  baud_rate: 19200
  id: uart_modbus
  stop_bits: 1
  
modbus:
  id: modbus_id
  uart_id: uart_modbus
  
modbus_controller:
  id: nilan_modbus_controller
  address: 30
  modbus_id: modbus_id
  update_interval: 30s
  
#external_components:
#  - source: github://Jopand/esphome_components@main
#    refresh: 0s

external_components:
  - source: github://woopstar/esphome_components@main
    refresh: 0s

nilan:

select:
  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Set operation mode"
    id: nilan_set_operation_mode
    address: 1002
    force_new_range: true
    use_write_multiple: true
    value_type: U_WORD
    optionsmap:
      "Off" : 0
      "Heat" : 1
      "Cool" : 2
      "Auto" : 3
      
binary_sensor:
  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Summer mode"
    id: nilan_is_summer
    register_type: read
    address: 1200
    bitmask: 1
  
  #- platform: modbus_controller
  #  modbus_controller_id: nilan_modbus_controller
  #  name: "Air filter alarm"
  #  id: nilan_filter_alarm
  #  register_type: read
  #  address: 101
  #  bitmask: 1

  - platform: template
    name: "Air filter alarm"
    id: nilan_filter_alarm
    lambda: !lambda |-
      return (id(nilan_alarm_list_1_id).state == 19
        || id(nilan_alarm_list_2_id).state == 19
        || id(nilan_alarm_list_3_id).state == 19);

  - platform: template
    id: nilan_bypass_state
    name: Bypass state
    device_class: opening
    
  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    id: nilan_bypass_open_request
    register_type: holding
    address: 102
    on_state: 
    - lambda: !lambda |-
        id(nilan_bypass_state).publish_state(true);
        
  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    id: nilan_bypass_close_request
    register_type: holding
    address: 103
    on_state: 
    - lambda: !lambda |-
        id(nilan_bypass_state).publish_state(false);
sensor:
  - platform: uptime
    name: "Nilan 300 Uptime"
    update_interval: 60s    
    
  - platform: wifi_signal
    name: "Nilan 300 WiFi Signal"
    update_interval: 60s    

  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Bus version"
    id: nilan_bus_version
    skip_updates: 60
    internal: true
    accuracy_decimals: 0
    entity_category: diagnostic
    register_type: read
    address: 0
    
  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Inlet (before heater) temperature"
    id: nilan_inlet_temp_t2
    unit_of_measurement: °C
    accuracy_decimals: 1
    device_class: temperature
    value_type: S_WORD
    register_type: read
    address: 202
    filters:
      - multiply: 0.01
      
  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Exhaust temperature"
    id: nilan_exhaust_temp_t3
    unit_of_measurement: °C
    accuracy_decimals: 1
    device_class: temperature
    value_type: S_WORD
    register_type: read
    address: 203
    filters:
      - multiply: 0.01
      
  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Outlet temperature"
    id: nilan_outlet_temp_t4
    unit_of_measurement: °C
    accuracy_decimals: 1
    device_class: temperature
    value_type: S_WORD
    register_type: read
    address: 204
    filters:
      - multiply: 0.01

  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Inlet (after heater) temperature"
    id: nilan_inlet_temp_t7
    unit_of_measurement: °C
    accuracy_decimals: 1
    device_class: temperature
    register_type: read
    address: 207
    filters:
      - multiply: 0.01

  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Outdoor temperature"
    id: nilan_outdoor_temp_t8
    unit_of_measurement: °C
    accuracy_decimals: 1
    device_class: temperature
    value_type: S_WORD
    register_type: read
    address: 208
    filters:
      - multiply: 0.01

  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Humidity"
    id: nilan_humidity
    unit_of_measurement: '%'
    accuracy_decimals: 1
    device_class: humidity
    register_type: read
    address: 221
    filters:
      - multiply: 0.01
    on_value: 
      - lambda: !lambda |-
          id(aqi_humidity).publish_state( (x < 35) ? "Too Dry" : 
                                          (x < 65) ? "Perfect" : 
                                          "Too Humid");

  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Exhaust fan speed"
    id: nilan_exhaust_fan_speed
    unit_of_measurement: '%'
    icon: "mdi:percent"
    accuracy_decimals: 0
    register_type: holding
    address: 200
    filters:
      - multiply: 0.01
  
  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Inlet fan speed"
    id: nilan_inlet_fan_speed
    unit_of_measurement: '%'
    icon: "mdi:percent"
    accuracy_decimals: 0
    register_type: holding
    address: 201
    filters:
      - multiply: 0.01

  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Controller temperature"
    id: nilan_controller_temp_t0
    unit_of_measurement: °C
    accuracy_decimals: 1
    device_class: temperature
    register_type: read
    address: 200
    filters:
      - multiply: 0.01

  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Room temperature"
    id: nilan_room_temp_t15
    unit_of_measurement: °C
    accuracy_decimals: 1
    device_class: temperature
    value_type: S_WORD
    register_type: read
    address: 215
    filters:
      - multiply: 0.01
      
  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Active alarms"
    id: nilan_active_alarms
    accuracy_decimals: 0
    register_type: read
    address: 400

  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Alarm list 1 id"
    id: nilan_alarm_list_1_id
    accuracy_decimals: 0
    register_type: read
    address: 401

  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    internal: true
    id: nilan_alarm_list_1_date
    accuracy_decimals: 0
    register_type: read
    address: 402
    
  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    internal: true
    id: nilan_alarm_list_1_time
    accuracy_decimals: 0
    register_type: read
    address: 403
    
  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Alarm list 2 id"
    id: nilan_alarm_list_2_id
    accuracy_decimals: 0
    register_type: read
    address: 404

  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    internal: true
    id: nilan_alarm_list_2_date
    accuracy_decimals: 0
    register_type: read
    address: 405
    
  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    internal: true
    id: nilan_alarm_list_2_time
    accuracy_decimals: 0
    register_type: read
    address: 406

  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Alarm list 3 id"
    id: nilan_alarm_list_3_id
    accuracy_decimals: 0
    register_type: read
    address: 407

  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    internal: true
    id: nilan_alarm_list_3_date
    accuracy_decimals: 0
    register_type: read
    address: 408
    
  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    internal: true
    id: nilan_alarm_list_3_time
    accuracy_decimals: 0
    register_type: read
    address: 409

  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Actual on/off state"
    id: nilan_actual_on_off_state
    accuracy_decimals: 0
    register_type: read
    address: 1000
    
  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "AirFlow.VentSet"
    id: nilan_airflow_vent_set
    accuracy_decimals: 0
    register_type: read
    address: 1100

  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "AirFlow.InletAct"
    id: nilan_airflow_inlet_act
    accuracy_decimals: 0
    register_type: read
    address: 1101

  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "AirFlow.ExhaustAct"
    id: nilan_airflow_exhaust_act
    accuracy_decimals: 0
    register_type: read
    address: 1102

  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Days since last air filter change alarm"
    id: nilan_days_since_last_air_filter_alarm
    accuracy_decimals: 0
    register_type: read
    address: 1103

  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Days to next air filter change alarm"
    id: nilan_days_to_next_air_filter_alarm
    accuracy_decimals: 0
    register_type: read
    address: 1104

  - platform: template
    name: "Calculated difference exhaust and inlet"
    id: calculated_value_inlet_exhaust
    icon: "mdi:thermometer"
    unit_of_measurement: °C
    update_interval: 10s
    lambda: 'return id(nilan_exhaust_temp_t3).state - id(nilan_inlet_temp_t7).state;'
    
  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Heat exchange efficiency"
    id: nilan_heat_exchange_efficiency
    unit_of_measurement: '%'
    accuracy_decimals: 1
    register_type: read
    address: 1204
    filters:
      - multiply: 0.01    
      
  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Cooling set temperature"
    id: nilan_cooling_set_temp
    unit_of_measurement: °C
    accuracy_decimals: 1
    device_class: temperature
    register_type: holding
    address: 1200
    filters:
      - multiply: 0.01
      
  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Min summer temperature"
    id: nilan_min_summer_temp
    unit_of_measurement: °C
    accuracy_decimals: 1
    device_class: temperature
    register_type: holding
    address: 1201
    filters:
      - multiply: 0.01 
  
  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Min winter temperature"
    id: nilan_min_winter_temp
    unit_of_measurement: °C
    accuracy_decimals: 1
    device_class: temperature
    register_type: holding
    address: 1202
    filters:
      - multiply: 0.01 
  
  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Max summer temperature"
    id: nilan_max_summer_temp
    unit_of_measurement: °C
    accuracy_decimals: 1
    device_class: temperature
    register_type: holding
    address: 1203
    filters:
      - multiply: 0.01 
  
#  - platform: modbus_controller
#    modbus_controller_id: nilan_modbus_controller
#    name: "Max winter temperature"
#    id: nilan_max_winter_temp
#    unit_of_measurement: °C
#    accuracy_decimals: 1
#    device_class: temperature
#    register_type: holding
#    address: 1204
#    filters:
#      - multiply: 0.01
      
number:
  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Ventilation speed set"
    id: nilan_ventilation_speed_set
    min_value: 0
    max_value: 4
    step: 1.0
    address: 1003
    force_new_range: true
    use_write_multiple: true


  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Temperature set"
    id: nilan_target_temperature_set
    min_value: 12
    max_value: 30
    step: 1.0
    address: 1004
    force_new_range: true
    use_write_multiple: true
    multiply: 100

  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Humidity low vent step"
    id: humidity_low_vent_step
    min_value: 0.0
    max_value: 4.0
    step: 1.0
    address: 1910
    force_new_range: true
    use_write_multiple: true
    
  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Humidity high vent step"
    id: humidity_high_vent_step
    min_value: 0.0
    max_value: 4.0
    step: 1.0
    address: 1911
    force_new_range: true
    use_write_multiple: true 

  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Humidity limit low vent"
    id: humidity_limit_low_vent    
    unit_of_measurement: '%'
    icon: "mdi:percent"
    min_value: 15.0
    max_value: 45.0
    step: 1.0
    address: 1912
    force_new_range: true
    use_write_multiple: true
    multiply: 100

  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Humidity max time on high ventilation (minutes)"
    id: humidity_max_time_high_vent
    value_type: U_WORD
    unit_of_measurement: minutes
    min_value: 0.0
    max_value: 180.0
    step: 1.0
    address: 1913
    force_new_range: true
    use_write_multiple: true
    icon: mdi:clock-start
    
text_sensor:
  - platform: template
    name: "Air Quality Index Humidity (AQI)"
    id: aqi_humidity
    icon: mdi:water-percent 

  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Operation mode"
    id: nilan_operation_mode
    register_type: read
    address: 1001
    lambda: !lambda |-
      uint16_t int_mode = (data[item->offset] << 8) + data[item->offset+1];
      ESP_LOGD("main","Parsed operation mode int : %d", int_mode);
      std::string mode_str;
      switch (int_mode) {
        case 0: mode_str = "Off"; break;
        case 1: mode_str = "Heat"; break;
        case 2: mode_str = "Cool"; break;
        case 3: mode_str = "Auto"; break;
        case 4: mode_str = "Service"; break;
        default: mode_str = "Unknown"; break;
      }
      return mode_str;
      
  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Control mode"
    id: nilan_control_state
    register_type: read
    address: 1002
    lambda: !lambda |-
      uint16_t int_mode = (data[item->offset] << 8) + data[item->offset+1];
      ESP_LOGD("main","Parsed operation mode int : %d", int_mode);
      std::string mode_str;
      switch (int_mode) {
        case 0:  mode_str = "Off"; break;
        case 1:  mode_str = "Shift"; break;
        case 2:  mode_str = "Stop"; break;
        case 3:  mode_str = "Start"; break;
        case 4:  mode_str = "Standby"; break;
        case 5:  mode_str = "Ventilation stop"; break;
        case 6:  mode_str = "Ventilation"; break;
        case 7:  mode_str = "Heating"; break;
        case 8:  mode_str = "Cooling"; break;
        case 9:  mode_str = "Hot water"; break;
        case 10: mode_str = "Legionella"; break;
        case 11: mode_str = "Cooling + hot water"; break;
        case 12: mode_str = "Central heating"; break;
        case 13: mode_str = "Defrost"; break;
        case 14: mode_str = "Frost secure"; break;
        case 15: mode_str = "Service"; break;
        case 16: mode_str = "Alarm"; break;
        default: mode_str = "Unknown"; break;
      }
      return mode_str;
      
  - platform: template
    name: "Alarm 1 timestamp"
    id: nilan_alarm_list_1_datetime
    lambda: |-
      uint16_t alarmDate = id(nilan_alarm_list_1_date).state;
      uint16_t alarmTime = id(nilan_alarm_list_1_time).state;
      
      if(!alarmDate ||!alarmTime) return std::string("");
      
      // Parse the date
      auto year = (alarmDate >> 9) + 1980;
      auto month = (alarmDate >> 5) & 0b00001111;
      auto day = alarmDate & 0b00011111;
      auto hour = (alarmTime >> 11) & 0b00011111;
      auto minute = (alarmTime >> 5) & 0b0011111;
      auto second = (alarmTime & 0b00011111) * 2;
      
      return std::to_string(year) + "-" +
        ((month < 10) ? "0" : "") + std::to_string(month) + "-" + 
        ((day < 10) ? "0" : "") + std::to_string(day) + " " +
        ((hour < 10) ? "0" : "") + std::to_string(hour) + ":" +
        ((minute < 10) ? "0" : "") + std::to_string(minute) + ":" +
        ((second < 10) ? "0" : "") + std::to_string(second);

  - platform: template
    name: "Alarm 2 timestamp"
    id: nilan_alarm_list_2_datetime
    lambda: |-
      uint16_t alarmDate = id(nilan_alarm_list_2_date).state;
      uint16_t alarmTime = id(nilan_alarm_list_2_time).state;
      
      if(!alarmDate ||!alarmTime) return std::string("");
      
      // Parse the date
      auto year = (alarmDate >> 9) + 1980;
      auto month = (alarmDate >> 5) & 0b00001111;
      auto day = alarmDate & 0b00011111;
      auto hour = (alarmTime >> 11) & 0b00011111;
      auto minute = (alarmTime >> 5) & 0b0011111;
      auto second = (alarmTime & 0b00011111) * 2;
      
      return std::to_string(year) + "-" +
        ((month < 10) ? "0" : "") + std::to_string(month) + "-" + 
        ((day < 10) ? "0" : "") + std::to_string(day) + " " +
        ((hour < 10) ? "0" : "") + std::to_string(hour) + ":" +
        ((minute < 10) ? "0" : "") + std::to_string(minute) + ":" +
        ((second < 10) ? "0" : "") + std::to_string(second);

  - platform: template
    name: "Alarm 3 timestamp"
    id: nilan_alarm_list_3_datetime
    lambda: |-
      uint16_t alarmDate = id(nilan_alarm_list_3_date).state;
      uint16_t alarmTime = id(nilan_alarm_list_3_time).state;
      
      if(!alarmDate ||!alarmTime) return std::string("");
      
      // Parse the date
      auto year = (alarmDate >> 9) + 1980;
      auto month = (alarmDate >> 5) & 0b00001111;
      auto day = alarmDate & 0b00011111;
      auto hour = (alarmTime >> 11) & 0b00011111;
      auto minute = (alarmTime >> 5) & 0b0011111;
      auto second = (alarmTime & 0b00011111) * 2;
      
      return std::to_string(year) + "-" +
        ((month < 10) ? "0" : "") + std::to_string(month) + "-" + 
        ((day < 10) ? "0" : "") + std::to_string(day) + " " +
        ((hour < 10) ? "0" : "") + std::to_string(hour) + ":" +
        ((minute < 10) ? "0" : "") + std::to_string(minute) + ":" +
        ((second < 10) ? "0" : "") + std::to_string(second);

  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Software version"
    id: nilan_version_info
    skip_updates: 60
    register_type: read
    register_count: 3
    response_size: 6
    address: 1
    entity_category: diagnostic
    lambda: !lambda |-
      float bus_version = nilan_bus_version->get_state();
      std::string output;
      
      if (bus_version == 8) {
        output = data[item->offset+1];
        output += data[item->offset+0];
        output += data[item->offset+3];
        output += data[item->offset+2];
        output += data[item->offset+5]; 
        output += data[item->offset+4];
      } else {  
        output = data[item->offset+0];
        output += data[item->offset+1];
        output += '.';
        output += data[item->offset+2];
        output += data[item->offset+3];
        output += '.';
        output += data[item->offset+4];
        output += data[item->offset+5];
      }
 
      ESP_LOGD("main","Parsed SW version: %s", output.c_str()); 
      return output;
      
  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "Aggregate type"
    id: nilan_platform_id
    skip_updates: 60
    entity_category: diagnostic
    register_type: holding
    address: 1000
    lambda: !lambda |-
      uint16_t int_type = (data[item->offset] << 8) + data[item->offset+1];
      ESP_LOGD("main","Parsed aggregate type int : %d", int_type);
      std::string type_str;
      switch (int_type) {
        case 0: type_str = "None"; break;
        case 1: type_str = "Test"; break;
        case 2: type_str = "VPL 10 uden køl"; break;
        case 3: type_str = "VPL 15 uden køl"; break;
        case 4: type_str = "VPL 15 med køl"; break;
        case 5: type_str = "VPL 25 med 3 hastigheder uden køl"; break;
        case 6: type_str = "VPL 25 med 3 hastigheder med køl"; break;
        case 7: type_str = "VPL 28 2 hastigheder uden køl"; break;
        case 8: type_str = "VPL 28 med 2 hastigheder med køl"; break;
        case 9: type_str = "VP 18 med kryds monteret oven på anlæg uden køl"; break;
        case 10: type_str = "VP 18 med kryds monteret oven på anlæg med køl"; break;
        case 11: type_str = "Vp 18 Compact og Compact p uden køl"; break;
        case 12: type_str = "VP 18 Compact og Compact P med køl"; break;
        case 13: type_str = "Comfort anlæg (Comfort 300 LR)"; break;
        case 14: type_str = "CT 150 anlæg med 1-2-3 omskifter"; break;
        case 15: type_str = "VLX som kører VAV"; break;
        case 16: type_str = "VLX med 2 trin"; break;
        case 17: type_str = "VLX med 3 trin"; break;
        case 18: type_str = "VP 18 uden køl"; break;
        case 19: type_str = "VP 18 med køl"; break;
        case 20: type_str = "VP 18 med elkedel uden køl"; break;
        case 21: type_str = "VP 18 med elkedel og køl"; break;
        case 22: type_str = "VGU 250 brugsvands varmepumpe"; break;
        case 23: type_str = "VGU 250 brugsvands varmepumpe med elkedel"; break;
        case 24: type_str = "VPL 25 uden køl"; break;
        case 25: type_str = "VPL 25 med køl"; break;
        case 26: type_str = "VPM 120-560"; break;
        case 27: type_str = "Comfort 1200 - 4000"; break;
        case 28: type_str = "VP 20 Compact gorona"; break;
        case 29: type_str = "VLX med CTS 602 print"; break;
        case 30: type_str = "Compact P Nordic"; break;
        case 31: type_str = "Comfort Nordic"; break;
        case 32: type_str = "VP 18 Version 1"; break;
        case 33: type_str = "Combi 300"; break;
        case 34: type_str = "Compact med 4-vejsventil uden køl"; break;
        default: type_str = "Unknown"; break;
      }
      return type_str;

switch:
  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    name: "On/Off state"
    id: nilan_on_off_state
    register_type: holding
    bitmask: 1
    force_new_range: true
    use_write_multiple: true
    address: 1001

climate:
  - platform: nilan
    name: Nilan
    current_temp_sensor_id: nilan_inlet_temp_t7
    target_temp_sensor_id: nilan_target_temperature_set
    fan_speed_sensor_id: nilan_ventilation_speed_set
    mode_select_id: nilan_set_operation_mode

output:
  - platform: modbus_controller
    modbus_controller_id: nilan_modbus_controller
    id: nilan_reset_alarm
    address: 400
    use_write_multiple: true
    value_type: U_WORD
    write_lambda: return 255;

button:
  - platform: output
    name: Reset alarm
    id: nilan_reset_alarm_button
    output: nilan_reset_alarm
    duration: 5s