ESP32 Board mit 4G Modul gesucht

Guten Morgen zusammen,

ich bin neu hier im Forum und auch generell neu in der Welt der ESP32 Boards, bitte nehmt mir meine Unwissenheit nicht übel.

Zu meinem Grundproblem bzw. meiner Ausgangssituation
(hat nur indirekt etwas mit den Boards zu tun, kann jedoch Hilfreich sein um mein Problem generell zu verstehen).

Ich möchte in meinem mobilen Camper die Standheizung bei mir in Homeassistant (betrieben bei mir Zuhause) einbinden. Hierbei bin ich auf eine Lösung gestoßen wo ein ESP32 Board eingesetzt wird. Die Herausforderung hier ist jedoch das diese Variante ausschließlich mit WiFi angegeben wurde, ich aber aus diversen Gründen hier kein eigenes Wireless Netzwerk aufbauen kann/möchte. Hier kam mir nun die Idee direkt mit einer SIM Karte zu arbeiten (Datacard bereits vorhanden bei dem Anbieter o2)

Mit ein paar Google Anfragen konnte ich bereits die ein oder anderen Boards mit integrierten 4G Modul auffinden. Da ich hier jedoch absolut keine Erfahrung mit habe, bin ich auf eure Hilfe/Ratschlag angewiesen.

Die bisherige Lösung ist hier wie folgt aufgebaut:

Hier wurde folgendes Board vorgesehen:

diymore 2 Stücke ESP32 WROOM 32 Nodemcu Development Board ESP32 NodeMCU Module USB C 2.4 GHz WLAN WiFi Bluetooth CH340 Chip

Link zu Amazon

Laut der Anleitung wird effektiv darauf hingewiesen das es essentiell ist das man hier ein ESP32 Board mit 2 UART Anschlüssen benötigt.

Nun zu meiner generellen Frage:

  • Gibt es hier ESP 32 Boards die den Anforderungen entsprechen (oder dem genannten Board ähneln) aber die Möglichkeit besitzen eine SIM Karte direkt zu verwenden?
  • Das ESP Board mit Sim Karte sollte die Möglichkeit besitzen eine VPN über Wireguard aufzubauen
  • Kann man eventuell das oben genannte Board mit einem Modul erweitern, wenn Ja mit welchem?

Der Code der hierfür vorgesehen ist:
--> Dieser hat noch keine Wireguard Anbindung

esphome:

  name: heater

  friendly_name: Heater

 

esp32:

  board: esp32dev

  framework:

    type: arduino

 

# Enable logging

logger:

    baud_rate: 0

 

# Enable Home Assistant API

api:

  encryption:

    key: "*************************"

 

ota:

  password: "*****************************"

 

wifi:

  ssid: ****************

  password: ********************

 

  # Enable fallback hotspot (captive portal) in case wifi connection fails

  ap:

    ssid: "Heater Fallback Hotspot"

    password: "********************"

 

captive_portal:

 

uart:

  - id: uart_1_controller

    baud_rate: 9600

    tx_pin: 17

    rx_pin: 16

    debug:

      direction: RX

      dummy_receiver: true

      after:

        delimiter: "\r\n"

      sequence:

        - uart.write: #Write rx to tx.

            id: uart_2_heater

            data: !lambda return bytes ;

        - lambda: |-

            ESP_LOGD("custom", "Controller:");

            UARTDebug::log_hex(direction, bytes, ':');

 

  - id: uart_2_heater

    baud_rate: 9600

    tx_pin: 1

    rx_pin: 3

    debug:

      direction: RX

      dummy_receiver: true

      after:

        delimiter: "\r\n"

      sequence:

        - uart.write: #Write rx to tx.

            id: uart_1_controller

            data: !lambda return bytes ;

        - lambda: |-

            ESP_LOGD("custom", "Heater:");

            UARTDebug::log_hex(direction, bytes, ':');

 

globals:

  - id: read_state

    type: int

    restore_value: no

    initial_value: '0'

  - id: message_length

    type: int

    restore_value: no

  - id: message_data

    type: std::vector<uint8_t>

    restore_value: no

  - id: heaterStatus

    type: int

    initial_value: '0'

  - id: connected

    type: bool

    initial_value: 'false'

  - id: tempSet

    type: int

    initial_value: '15'

    restore_value: no

  - id: powerSet

    type: int

    initial_value: '2'

    restore_value: no

 

script:

  - id: send_uart_command

    then:

      - lambda: |-

          std::vector<uint8_t> byteArray = {0xAA, 0x03, 0x06, 0x00, 0x01, 0xFF, 0xFF

          , (uint8_t) static_cast<uint8_t>(id(power_mode_slider).state)

          , (uint8_t) static_cast<uint8_t>(id(tempSet))

          , (uint8_t) static_cast<uint8_t>(id(ventilation_slider).state)

          , (uint8_t) static_cast<uint8_t>(id(powerSet))};

          uint16_t crc = 0xFFFF;

          for (uint8_t pos = 0; pos < byteArray.size(); pos++) {

              crc ^= byteArray[pos];

              for (uint8_t i = 0; i < 8; i++) {

                  bool odd = crc & 0x0001;

                  crc >>= 1;

                  if (odd) {

                      crc ^= 0xA001;

                  }

              }

          }

          byteArray.push_back((crc >> 8) & 0xff);

          byteArray.push_back(crc & 0xff);

          id(uart_2_heater).write_array(&byteArray[0], byteArray.size());

          /*for (uint8_t i = 0; i < byteArray.size(); i++) {

              ESP_LOGD("send_uart_command", "byteArray[%d] = %02X", i, byteArray[i]);

          }*/

  - id: update_Settings_uart_command

    then:

      - lambda: |-

          ESP_LOGD("Updating", "");

          std::vector<uint8_t> byteArray = {0xAA, 0x03, 0x06, 0x00, 0x02, 0xFF, 0xFF

          , (uint8_t) static_cast<uint8_t>(id(power_mode_slider).state)

          , (uint8_t) static_cast<uint8_t>(id(tempSet))

          , (uint8_t) static_cast<uint8_t>(id(ventilation_slider).state)

          , (uint8_t) static_cast<uint8_t>(id(powerSet))};

          uint16_t crc = 0xFFFF;

          for (uint8_t pos = 0; pos < byteArray.size(); pos++) {

              crc ^= byteArray[pos];

              for (uint8_t i = 0; i < 8; i++) {

                  bool odd = crc & 0x0001;

                  crc >>= 1;

                  if (odd) {

                      crc ^= 0xA001;

                  }

              }

          }

          byteArray.push_back((crc >> 8) & 0xff);

          byteArray.push_back(crc & 0xff);

          id(uart_2_heater).write_array(&byteArray[0], byteArray.size());

          for (uint8_t i = 0; i < byteArray.size(); i++) {

              ESP_LOGD("send_uart_command", "byteArray[%d] = %02X", i, byteArray[i]);

          }

 

switch:

  - platform: uart

    uart_id: uart_2_heater

    name: "TurnOnHeaterP3V1heater"

    data: [0xAA, 0x03, 0x06, 0x00, 0x01, 0xFF, 0xFF, 0x01, 0x0F, 0x00, 0x05, 0xB6, 0x1F]

  - platform: uart

    uart_id: uart_2_heater

    name: "Turn On Heater in T panel Mode"

    data: [0xAA, 0x03, 0x06, 0x00, 0x01, 0xFF, 0xFF, 0x02, 0x0F, 0x02, 0x05, 0x92, 0x1E]

  - platform: template

    name: "Controllable Heater Start"

    lambda: |-

      if (id(heaterStatus) != 0) {

        return true;

      } else {

        return false;

      }

    turn_on_action:

      - script.execute: send_uart_command

    turn_off_action:

      uart.write:

          id: uart_2_heater

          data: [0xAA, 0x03, 0x00, 0x00, 0x03, 0x5D, 0x7C]

  - platform: uart

    uart_id: uart_2_heater

    name: "Shutdown"

    data: [0xAA, 0x03, 0x00, 0x00, 0x03, 0x5D, 0x7C]

  - platform: template

    name: "Ventillator Power"

    turn_on_action:

      -  uart.write:

            id: uart_2_heater

            data: [0xAA, 0x03, 0x04, 0x00, 0x23, 0xFF, 0xFF, 0x08, 0xFF]

    turn_off_action:

      -  uart.write:

            id: uart_2_heater

            data: [0xAA, 0x03, 0x00, 0x00, 0x03]

   

 

sensor:

  - platform: template

    name: "Heater Status"

    id: heater_status

    update_interval: 1s

  - platform: template

    name: "Heater Battery Voltage"

    id: heater_battery_voltage

    update_interval: 1s

    unit_of_measurement: "V"

    icon: "mdi:battery"

  - platform: template

    name: "Heater Ventilation Power"

    id: heater_ventilation_power

    update_interval: 1s

    unit_of_measurement: "W"

  - platform: template

    name: "Heater Temperature"

    id: heater_temperature

    update_interval: 1s

    unit_of_measurement: "°C"

    icon: "mdi:thermometer"

  - platform: template

    name: "Heater Temperature By Panel"

    id: heater_temperature_panel

    unit_of_measurement: "°C"

    icon: "mdi:thermometer"

    update_interval: 1s

  - platform: template

    name: "Heater Power"

    id: heater_power_status

    update_interval: 1s

    unit_of_measurement: '%'

  - platform: template

    name: "Set Temperature"

    id: set_temperature

    update_interval: 1s

    unit_of_measurement: "°C"

    icon: "mdi:thermometer"

  - platform: template

    name: "Air Temperature"

    id: air_temperature

    update_interval: 1s

    unit_of_measurement: "°C"

    icon: "mdi:thermometer"

number:

  - platform: template

    name: "temperature Slider"

    id: "temperature_slider"

    step: 1

    min_value: 0

    max_value: 30

    mode: slider

    initial_value: '15'

    optimistic: true

    set_action:

      lambda: |-

          id(tempSet)=x;

          id(update_Settings_uart_command).execute();

 

  - platform: template

    name: "power Slider"

    id: "power_slider"

    step: 1

    min_value: 1

    max_value: 10

    initial_value: '3'

    mode: slider

    optimistic: true

    set_action:

      lambda: |-

          id(powerSet)=x-1;

          id(update_Settings_uart_command).execute();

           int modeValue = id(power_slider).state;  // Änderung hier zu power_slider

            std::map<int, std::string> modes = {{1, "By T Heater"}, {2, "By T Panel"}, {3, "By T Air"}, {4, "Power Mode"}};

            if (modes.find(modeValue) != modes.end()) {

              id(power_mode_text).publish_state(modes[modeValue]);

            } else {

              id(power_mode_text).publish_state("Unknown");

            }

  - platform: template

    name: "power mode Slider"

    id: "power_mode_slider"

    step: 1

    min_value: 1

    max_value: 4

    mode: slider

    optimistic: true

    set_action:

      then:

        - script.execute: update_Settings_uart_command

  - platform: template

    name: "ventilation on/off Slider"

    id: "ventilation_slider"

    step: 1

    min_value: 1

    max_value: 2

    mode: slider

    optimistic: true

    set_action:

      then:

        - script.execute: update_Settings_uart_command

 

text_sensor:

  - platform: template

    name: "Power Mode Text"

    id: power_mode_text

    update_interval: 10s

     

  - platform: template

    name: "Heater Ventillator Mode Text"

    id: heater_ventillator_mode_text

    update_interval: 10s

 

interval:

  - interval: 20ms

    then:

      - lambda: |-

          static uint8_t command_id = 0;

          while (id(uart_2_heater).available())

          {

            uint8_t byte;

            id(uart_2_heater).read_byte(&byte);

            if (id(read_state) == 0 && byte == 0xAA)

            {

              // Start of message

              id(read_state) = 1;

              id(message_data).clear();

            }

            else if (id(read_state) == 1)

            {

              id(read_state) = 2;

            }

            else if (id(read_state) == 2)

            {

              // Message length

              id(message_length) = byte;

              id(read_state) = 3;

            }

            else if (id(read_state) == 3)

            {

              // 00

              id(read_state) = 4;

            }

              else if (id(read_state) == 4)

            {

              // this is command id

              id(read_state) = 5;

              command_id=byte;

            }

              else if(id(read_state) == 5)

            {

              id(message_data).push_back(byte);

              if (id(message_data).size() >= id(message_length))

              {

                if (command_id==15)

                {

                  id(connected)=true;

                  int temperature_calc_heater = id(message_data)[3];

                  //ESP_LOGD("send_uart_command","Temp Message", id(message_data)[3]);

                    if (temperature_calc_heater > 127) {

                  //    ESP_LOGD("send_uart_command","Temp temperature_calc_heater", temperature_calc_heater);

                      temperature_calc_heater = (temperature_calc_heater -256);

                  //    ESP_LOGD("send_uart_command","Temp temperature_calc_heater_calculated", temperature_calc_heater);

                    }

                  id(heater_temperature).publish_state(temperature_calc_heater);

                  //id(heater_temperature).publish_state(id(message_data)[3]);

                  id(heater_status).publish_state(id(message_data)[9]);

                  uint8_t statusByte = id(message_data)[9];

                  int value = static_cast<int>(statusByte);

                  id(heaterStatus) = value;

                  id(heater_battery_voltage).publish_state(id(message_data)[6] / 10.0);

                  id(heater_ventilation_power).publish_state((id(message_data)[16]));

                  int temperature_calc_air = id(message_data)[4];

                  //ESP_LOGD("send_uart_command","Temp Message", id(message_data)[4]);

                    if (temperature_calc_air > 127) {

                  //    ESP_LOGD("send_uart_command","Temp temperature_calc_air", temperature_calc_air);

                      temperature_calc_air = (temperature_calc_air -256);

                  //    ESP_LOGD("send_uart_command","Temp temperature_calc_air_calculated", temperature_calc_air);

                    }

                  id(air_temperature).publish_state(temperature_calc_air);

                }

                else if (command_id==17)

                {

                  int temperature_calc_panel = id(message_data)[0];

                  //ESP_LOGD("send_uart_command","Temp Message", id(message_data)[0]);

                    if (temperature_calc_panel > 127) {

                  //    ESP_LOGD("send_uart_command","Temp temperature_calc_panel", temperature_calc_panel);

                      temperature_calc_panel = (temperature_calc_panel -256);

                  //    ESP_LOGD("send_uart_command","Temp temperature_calc_panel_calculated", temperature_calc_panel);

                    }

                  id(heater_temperature_panel).publish_state(temperature_calc_panel);

                  //id(temperature_heater).publish_state(id(message_data)[0]);

                }

                else if (command_id==2 && id(heaterStatus)!=0)

                {

                  id(set_temperature).publish_state(id(message_data)[3]);

                  id(heater_power_status).publish_state(id(message_data)[5]+1);

                  std::map<uint32_t, std::string> modes = {{1, "By T Heater"}, {2, "By T Panel"}, {3, "By T Air"}, {4, "By Power"}};

                  uint32_t mode = round(id(message_data)[2]);

                  if (modes.find(mode) != modes.end()) {

                    id(power_mode_text).publish_state(modes[mode]);

                  } else {

                    id(power_mode_text).publish_state("Unknown");

                  }

                  modes = {{1, "On"}, {2, "Off"}};

                  mode = round(id(message_data)[4]);

                  if (modes.find(mode) != modes.end()) {

                    id(heater_ventillator_mode_text).publish_state(modes[mode]);

                  } else {

                    id(heater_ventillator_mode_text).publish_state("Unknown");

                  }

 

                  //id(power_mode_slider).publish_state(id(message_data)[2]);

                  //id(ventilation_slider).publish_state(id(message_data)[4]);

                  if(id(temperature_slider).state!=id(message_data)[3])

                    id(temperature_slider).publish_state(id(message_data)[3]);

                  if(id(power_slider).state!=id(message_data)[5])

                    id(power_slider).publish_state(id(message_data)[5]+1);

                }

                id(read_state) = 0;

              }

            }

          }

 

 

 

 

 

Ich bedanke mich schon mal recht Herzlich für eure Unterstützung und eurer Zeit.

Viele Grüße,

Maik L.

heißt das dein Homeassistant läuft im Camper oder wo stationär?

Der Plan ist das mein Homeassistant von mir Daheim von Remote angesprochen wird, deshalb die Überlegung mit Wireguard.

Ich hätte auch die Möglichkeit mit einem Raspi 4 lokal im Camper ein Homeassistant zu betreiben, möchte aber gerne nur eine Oberfläche zum steuern von Zuhause und Camper (Standheizung) haben.