diff --git a/esphome/components/modem/text_sensor/__init__.py b/esphome/components/modem/text_sensor/__init__.py new file mode 100644 index 0000000000..7922bfca6d --- /dev/null +++ b/esphome/components/modem/text_sensor/__init__.py @@ -0,0 +1,45 @@ +import esphome.codegen as cg +from esphome.components import text_sensor +from esphome.components.modem import final_validate_platform +import esphome.config_validation as cv +from esphome.const import CONF_ID, DEVICE_CLASS_EMPTY + +CODEOWNERS = ["@oarcher"] + +AUTO_LOAD = [] + +DEPENDENCIES = ["modem"] + +# MULTI_CONF = True +IS_PLATFORM_COMPONENT = True + +CONF_NETWORK_TYPE = "network_type" + +modem_text_sensor_ns = cg.esphome_ns.namespace("modem_text_sensor") +ModemTextSensorComponent = modem_text_sensor_ns.class_( + "ModemTextSensor", cg.PollingComponent +) + + +CONFIG_SCHEMA = cv.All( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(ModemTextSensorComponent), + cv.Optional(CONF_NETWORK_TYPE): text_sensor.text_sensor_schema( + device_class=DEVICE_CLASS_EMPTY, + ), + } + ).extend(cv.polling_component_schema("60s")) +) + + +FINAL_VALIDATE_SCHEMA = final_validate_platform + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + if network_type := config.get(CONF_NETWORK_TYPE, None): + network_type_text_sensor = await text_sensor.new_text_sensor(network_type) + cg.add(var.set_network_type_text_sensor(network_type_text_sensor)) + + await cg.register_component(var, config) diff --git a/esphome/components/modem/text_sensor/modem_text_sensor.cpp b/esphome/components/modem/text_sensor/modem_text_sensor.cpp new file mode 100644 index 0000000000..d1cf2088bc --- /dev/null +++ b/esphome/components/modem/text_sensor/modem_text_sensor.cpp @@ -0,0 +1,121 @@ +#ifdef USE_ESP_IDF + +#include "esphome/core/defines.h" + +#ifdef USE_MODEM +#ifdef USE_TEXT_SENSOR + +#include "modem_text_sensor.h" + +#include "esphome/core/log.h" +#include "esphome/core/application.h" + +// #include "esphome/components/watchdog/watchdog.h" +#include "esphome/components/modem/modem_component.h" + +#define ESPHL_ERROR_CHECK(err, message) \ + if ((err) != ESP_OK) { \ + ESP_LOGE(TAG, message ": (%d) %s", err, esp_err_to_name(err)); \ + this->mark_failed(); \ + return; \ + } + +#define ESPMODEM_ERROR_CHECK(err, message) \ + if ((err) != command_result::OK) { \ + ESP_LOGE(TAG, message ": %s", command_result_to_string(err).c_str()); \ + } + +namespace esphome { +namespace modem_text_sensor { + +using namespace esp_modem; +// using namespace esphome::modem; + +void ModemTextSensor::setup() { ESP_LOGI(TAG, "Setting up Modem Sensor..."); } + +void ModemTextSensor::update() { + ESP_LOGD(TAG, "Modem text_sensor update"); + if (modem::global_modem_component->dce && modem::global_modem_component->modem_ready()) { + this->update_network_type_text_sensor_(); + } +} + +void ModemTextSensor::update_network_type_text_sensor_() { + if (modem::global_modem_component->modem_ready() && this->network_type_text_sensor_) { + int act; + std::string network_type = "Not available"; + if (modem::global_modem_component->dce->get_network_system_mode(act) == command_result::OK) { + // Access Technology from AT+CNSMOD? + // see https://www.waveshare.com/w/upload/a/af/SIM7500_SIM7600_Series_AT_Command_Manual_V3.00.pdf, page 109 + switch (act) { + case 0: + network_type = "No service"; + break; + case 1: + network_type = "GSM"; + break; + case 2: + network_type = "GPRS"; + break; + case 3: + network_type = "EGPRS (EDGE)"; + break; + case 4: + network_type = "WCDMA"; + break; + case 5: + network_type = "HSDPA only (WCDMA)"; + break; + case 6: + network_type = "HSUPA only (WCDMA)"; + break; + case 7: + network_type = "HSPA (HSDPA and HSUPA, WCDMA)"; + break; + case 8: + network_type = "LTE"; + break; + case 9: + network_type = "TDS-CDMA"; + break; + case 10: + network_type = "TDS-HSDPA only"; + break; + case 11: + network_type = "TDS-HSUPA only"; + break; + case 12: + network_type = "TDS-HSPA (HSDPA and HSUPA)"; + break; + case 13: + network_type = "CDMA"; + break; + case 14: + network_type = "EVDO"; + break; + case 15: + network_type = "HYBRID (CDMA and EVDO)"; + break; + case 16: + network_type = "1XLTE (CDMA and LTE)"; + break; + case 23: + network_type = "EHRPD"; + break; + case 24: + network_type = "HYBRID (CDMA and EHRPD)"; + break; + default: + network_type = "Unknown"; + } + } + this->network_type_text_sensor_->publish_state(network_type); + } +} + +} // namespace modem_text_sensor +} // namespace esphome + +#endif // USE_MODEM +#endif // USE_TEXT_SENSOR +#endif // USE_ESP_IDF diff --git a/esphome/components/modem/text_sensor/modem_text_sensor.h b/esphome/components/modem/text_sensor/modem_text_sensor.h new file mode 100644 index 0000000000..e173a06391 --- /dev/null +++ b/esphome/components/modem/text_sensor/modem_text_sensor.h @@ -0,0 +1,41 @@ +#pragma once +#ifdef USE_ESP_IDF + +#include "esphome/core/defines.h" + +#ifdef USE_MODEM +#ifdef USE_TEXT_SENSOR + +#include "esphome/core/component.h" +#include "esphome/components/modem/modem_component.h" +#include "esphome/components/text_sensor/text_sensor.h" + +namespace esphome { +namespace modem_text_sensor { + +static const char *const TAG = "modem_text_sensor"; + +class ModemTextSensor : public PollingComponent { + public: + void set_network_type_text_sensor(text_sensor::TextSensor *network_type_text_sensor) { + this->network_type_text_sensor_ = network_type_text_sensor; + } + // ========== INTERNAL METHODS ========== + // (In most use cases you won't need these) + + float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } + void setup() override; + void update() override; + void dump_config() override {} + + protected: + text_sensor::TextSensor *network_type_text_sensor_{nullptr}; + void update_network_type_text_sensor_(); +}; + +} // namespace modem_text_sensor +} // namespace esphome + +#endif // USE_MODEM +#endif // USE_TEXT_SENSOR +#endif // USE_ESP_IDF