mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	gnss as a switch
This commit is contained in:
		| @@ -262,6 +262,7 @@ esphome/components/modbus_controller/switch/* @martgras | |||||||
| esphome/components/modbus_controller/text_sensor/* @martgras | esphome/components/modbus_controller/text_sensor/* @martgras | ||||||
| esphome/components/modem/* @oarcher | esphome/components/modem/* @oarcher | ||||||
| esphome/components/modem/sensor/* @oarcher | esphome/components/modem/sensor/* @oarcher | ||||||
|  | esphome/components/modem/switch/* @oarcher | ||||||
| esphome/components/modem/text_sensor/* @oarcher | esphome/components/modem/text_sensor/* @oarcher | ||||||
| esphome/components/mopeka_ble/* @Fabian-Schmidt @spbrogan | esphome/components/mopeka_ble/* @Fabian-Schmidt @spbrogan | ||||||
| esphome/components/mopeka_pro_check/* @spbrogan | esphome/components/mopeka_pro_check/* @spbrogan | ||||||
|   | |||||||
| @@ -40,7 +40,6 @@ CONF_POWER_PIN = "power_pin" | |||||||
| CONF_INIT_AT = "init_at" | CONF_INIT_AT = "init_at" | ||||||
| CONF_ON_NOT_RESPONDING = "on_not_responding" | CONF_ON_NOT_RESPONDING = "on_not_responding" | ||||||
| CONF_ENABLE_CMUX = "enable_cmux" | CONF_ENABLE_CMUX = "enable_cmux" | ||||||
| CONF_ENABLE_GNSS = "enable_gnss" |  | ||||||
|  |  | ||||||
| MODEM_MODELS = ["BG96", "SIM800", "SIM7000", "SIM7600", "SIM7670", "GENERIC"] | MODEM_MODELS = ["BG96", "SIM800", "SIM7000", "SIM7600", "SIM7670", "GENERIC"] | ||||||
| MODEM_MODELS_POWER = { | MODEM_MODELS_POWER = { | ||||||
| @@ -52,10 +51,6 @@ MODEM_MODELS_POWER = { | |||||||
|  |  | ||||||
| MODEM_MODELS_POWER["SIM7670"] = MODEM_MODELS_POWER["SIM7600"] | MODEM_MODELS_POWER["SIM7670"] = MODEM_MODELS_POWER["SIM7600"] | ||||||
|  |  | ||||||
| # SIM70xx doesn't support AT+CGNSSINFO, so gnss is not available |  | ||||||
| MODEM_MODELS_GNSS_POWER = {"SIM7600": "AT+CGPS=1", "SIM7670": "AT+CGNSSPWR=1"} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| modem_ns = cg.esphome_ns.namespace("modem") | modem_ns = cg.esphome_ns.namespace("modem") | ||||||
| ModemComponent = modem_ns.class_("ModemComponent", cg.Component) | ModemComponent = modem_ns.class_("ModemComponent", cg.Component) | ||||||
| ModemComponentState = modem_ns.enum("ModemComponentState") | ModemComponentState = modem_ns.enum("ModemComponentState") | ||||||
| @@ -69,7 +64,6 @@ ModemOnDisconnectTrigger = modem_ns.class_( | |||||||
|     "ModemOnDisconnectTrigger", automation.Trigger.template() |     "ModemOnDisconnectTrigger", automation.Trigger.template() | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  |  | ||||||
| CONFIG_SCHEMA = cv.All( | CONFIG_SCHEMA = cv.All( | ||||||
|     cv.Schema( |     cv.Schema( | ||||||
|         { |         { | ||||||
| @@ -89,7 +83,6 @@ CONFIG_SCHEMA = cv.All( | |||||||
|             cv.Optional(CONF_ENABLE_ON_BOOT, default=True): cv.boolean, |             cv.Optional(CONF_ENABLE_ON_BOOT, default=True): cv.boolean, | ||||||
|             cv.Optional(CONF_ENABLE_CMUX, default=False): cv.boolean, |             cv.Optional(CONF_ENABLE_CMUX, default=False): cv.boolean, | ||||||
|             cv.Optional(CONF_DEBUG, default=False): cv.boolean,  # needs also |             cv.Optional(CONF_DEBUG, default=False): cv.boolean,  # needs also | ||||||
|             cv.Optional(CONF_ENABLE_GNSS, default=False): cv.boolean, |  | ||||||
|             cv.Optional(CONF_ON_NOT_RESPONDING): automation.validate_automation( |             cv.Optional(CONF_ON_NOT_RESPONDING): automation.validate_automation( | ||||||
|                 { |                 { | ||||||
|                     cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id( |                     cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id( | ||||||
| @@ -138,11 +131,6 @@ def _final_validate(config): | |||||||
|             raise cv.Invalid( |             raise cv.Invalid( | ||||||
|                 f"Modem model '{config[CONF_MODEL]}' has no power power specs." |                 f"Modem model '{config[CONF_MODEL]}' has no power power specs." | ||||||
|             ) |             ) | ||||||
|     if config.get(CONF_ENABLE_GNSS, None): |  | ||||||
|         if config[CONF_MODEL] not in MODEM_MODELS_GNSS_POWER: |  | ||||||
|             raise cv.Invalid( |  | ||||||
|                 f"Modem model '{config[CONF_MODEL]}' has no GNSS support with AT+CGNSSINFO." |  | ||||||
|             ) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| FINAL_VALIDATE_SCHEMA = _final_validate | FINAL_VALIDATE_SCHEMA = _final_validate | ||||||
| @@ -199,9 +187,6 @@ async def to_code(config): | |||||||
|     modem_model = config[CONF_MODEL] |     modem_model = config[CONF_MODEL] | ||||||
|     cg.add(var.set_model(modem_model)) |     cg.add(var.set_model(modem_model)) | ||||||
|  |  | ||||||
|     if config[CONF_ENABLE_GNSS]: |  | ||||||
|         cg.add(var.set_gnss_power_command(MODEM_MODELS_GNSS_POWER[modem_model])) |  | ||||||
|  |  | ||||||
|     if power_spec := MODEM_MODELS_POWER.get(modem_model, None): |     if power_spec := MODEM_MODELS_POWER.get(modem_model, None): | ||||||
|         cg.add(var.set_power_ton(power_spec["ton"])) |         cg.add(var.set_power_ton(power_spec["ton"])) | ||||||
|         cg.add(var.set_power_tonuart(power_spec["tonuart"])) |         cg.add(var.set_power_tonuart(power_spec["tonuart"])) | ||||||
|   | |||||||
| @@ -39,6 +39,8 @@ namespace modem { | |||||||
|  |  | ||||||
| using namespace esp_modem; | using namespace esp_modem; | ||||||
|  |  | ||||||
|  | static const char *const TAG = "modem"; | ||||||
|  |  | ||||||
| ModemComponent *global_modem_component = nullptr;  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) | ModemComponent *global_modem_component = nullptr;  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) | ||||||
|  |  | ||||||
| ModemComponent::ModemComponent() { | ModemComponent::ModemComponent() { | ||||||
| @@ -49,7 +51,7 @@ ModemComponent::ModemComponent() { | |||||||
| void ModemComponent::enable_debug() { esp_log_level_set("command_lib", ESP_LOG_VERBOSE); } | void ModemComponent::enable_debug() { esp_log_level_set("command_lib", ESP_LOG_VERBOSE); } | ||||||
|  |  | ||||||
| std::string ModemComponent::send_at(const std::string &cmd) { | std::string ModemComponent::send_at(const std::string &cmd) { | ||||||
|   std::string result = "ERROR"; |   std::string result = ""; | ||||||
|   command_result status = command_result::FAIL; |   command_result status = command_result::FAIL; | ||||||
|   ESP_LOGV(TAG, "Sending command: %s", cmd.c_str()); |   ESP_LOGV(TAG, "Sending command: %s", cmd.c_str()); | ||||||
|   if (this->modem_ready()) { |   if (this->modem_ready()) { | ||||||
| @@ -57,6 +59,9 @@ std::string ModemComponent::send_at(const std::string &cmd) { | |||||||
|     ESP_LOGV(TAG, "Result for command %s: %s (status %s)", cmd.c_str(), result.c_str(), |     ESP_LOGV(TAG, "Result for command %s: %s (status %s)", cmd.c_str(), result.c_str(), | ||||||
|              command_result_to_string(status).c_str()); |              command_result_to_string(status).c_str()); | ||||||
|   } |   } | ||||||
|  |   if (status != command_result::OK) { | ||||||
|  |     result = "ERROR"; | ||||||
|  |   } | ||||||
|   return result; |   return result; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -547,19 +552,6 @@ bool ModemComponent::modem_sync_() { | |||||||
|     // First time the modem is synced, or modem recovered |     // First time the modem is synced, or modem recovered | ||||||
|     this->internal_state_.modem_synced = true; |     this->internal_state_.modem_synced = true; | ||||||
|  |  | ||||||
|     if (!this->gnss_power_command_.empty()) { |  | ||||||
|       command_result err; |  | ||||||
|       ESP_LOGD(TAG, "Enabling GNSS with command: %s", this->gnss_power_command_.c_str()); |  | ||||||
|       err = this->dce->at(this->gnss_power_command_, result, this->command_delay_); |  | ||||||
|       if (err == command_result::FAIL) { |  | ||||||
|         // AT+CGPS=1 for SIM7600 or AT+CGNSSPWR=1 for SIM7670 often fail, but seems to be working anyway |  | ||||||
|         ESP_LOGD(TAG, "GNSS power command failed. Ignoring, as the status is often FAIL, while it works later."); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     // ESPMODEM_ERROR_CHECK(this->dce->set_gnss_power_mode(0), "Enabling/disabling GNSS"); |  | ||||||
|  |  | ||||||
|     // delay(200);  // NOLINT |  | ||||||
|  |  | ||||||
|     if (!this->prepare_sim_()) { |     if (!this->prepare_sim_()) { | ||||||
|       // fatal error |       // fatal error | ||||||
|       this->disable(); |       this->disable(); | ||||||
| @@ -567,8 +559,6 @@ bool ModemComponent::modem_sync_() { | |||||||
|     } |     } | ||||||
|     this->send_init_at_(); |     this->send_init_at_(); | ||||||
|  |  | ||||||
|     // ESPMODEM_ERROR_CHECK(this->dce->set_gnss_power_mode(this->gnss_), "Enabling/disabling GNSS"); |  | ||||||
|  |  | ||||||
|     ESP_LOGI(TAG, "Modem infos:"); |     ESP_LOGI(TAG, "Modem infos:"); | ||||||
|     std::string result; |     std::string result; | ||||||
|     ESPMODEM_ERROR_CHECK(this->dce->get_module_name(result), "get_module_name"); |     ESPMODEM_ERROR_CHECK(this->dce->get_module_name(result), "get_module_name"); | ||||||
|   | |||||||
| @@ -28,8 +28,6 @@ namespace modem { | |||||||
|  |  | ||||||
| using namespace esp_modem; | using namespace esp_modem; | ||||||
|  |  | ||||||
| static const char *const TAG = "modem"; |  | ||||||
|  |  | ||||||
| enum class ModemComponentState { | enum class ModemComponentState { | ||||||
|   NOT_RESPONDING, |   NOT_RESPONDING, | ||||||
|   DISCONNECTED, |   DISCONNECTED, | ||||||
| @@ -49,7 +47,7 @@ class ModemComponent : public Component { | |||||||
|   void set_use_address(const std::string &use_address) { this->use_address_ = use_address; } |   void set_use_address(const std::string &use_address) { this->use_address_ = use_address; } | ||||||
|   void set_rx_pin(InternalGPIOPin *rx_pin) { this->rx_pin_ = rx_pin; } |   void set_rx_pin(InternalGPIOPin *rx_pin) { this->rx_pin_ = rx_pin; } | ||||||
|   void set_tx_pin(InternalGPIOPin *tx_pin) { this->tx_pin_ = tx_pin; } |   void set_tx_pin(InternalGPIOPin *tx_pin) { this->tx_pin_ = tx_pin; } | ||||||
|   void set_model(const std::string model) { this->model_ = model; } |   void set_model(const std::string &model) { this->model_ = model; } | ||||||
|   void set_power_pin(GPIOPin *power_pin) { this->power_pin_ = power_pin; } |   void set_power_pin(GPIOPin *power_pin) { this->power_pin_ = power_pin; } | ||||||
|   void set_power_ton(int ton) { this->power_ton_ = ton; } |   void set_power_ton(int ton) { this->power_ton_ = ton; } | ||||||
|   void set_power_tonuart(int tonuart) { this->power_tonuart_ = tonuart; } |   void set_power_tonuart(int tonuart) { this->power_tonuart_ = tonuart; } | ||||||
| @@ -60,8 +58,8 @@ class ModemComponent : public Component { | |||||||
|   void set_password(const std::string &password) { this->password_ = password; } |   void set_password(const std::string &password) { this->password_ = password; } | ||||||
|   void set_pin_code(const std::string &pin_code) { this->pin_code_ = pin_code; } |   void set_pin_code(const std::string &pin_code) { this->pin_code_ = pin_code; } | ||||||
|   void set_apn(const std::string &apn) { this->apn_ = apn; } |   void set_apn(const std::string &apn) { this->apn_ = apn; } | ||||||
|   void set_gnss_power_command(const std::string &at_command) { this->gnss_power_command_ = at_command; } |   // void set_gnss_power_command(const std::string &at_command) { this->gnss_power_command_ = at_command; } | ||||||
|   std::string get_gnss_power_command() { return this->gnss_power_command_; } |   // std::string get_gnss_power_command() { return this->gnss_power_command_; } | ||||||
|   void set_not_responding_cb(Trigger<> *not_responding_cb) { this->not_responding_cb_ = not_responding_cb; } |   void set_not_responding_cb(Trigger<> *not_responding_cb) { this->not_responding_cb_ = not_responding_cb; } | ||||||
|   void enable_cmux() { this->cmux_ = true; } |   void enable_cmux() { this->cmux_ = true; } | ||||||
|   void enable_debug(); |   void enable_debug(); | ||||||
| @@ -130,7 +128,6 @@ class ModemComponent : public Component { | |||||||
|   std::vector<std::string> init_at_commands_; |   std::vector<std::string> init_at_commands_; | ||||||
|   std::string use_address_; |   std::string use_address_; | ||||||
|   bool cmux_{false}; |   bool cmux_{false}; | ||||||
|   std::string gnss_power_command_; |  | ||||||
|   // separate handler for `on_not_responding` (we want to know when it's ended) |   // separate handler for `on_not_responding` (we want to know when it's ended) | ||||||
|   Trigger<> *not_responding_cb_{nullptr}; |   Trigger<> *not_responding_cb_{nullptr}; | ||||||
|   CallbackManager<void(ModemComponentState, ModemComponentState)> on_state_callback_; |   CallbackManager<void(ModemComponentState, ModemComponentState)> on_state_callback_; | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ from esphome.const import ( | |||||||
|     CONF_ID, |     CONF_ID, | ||||||
|     CONF_LATITUDE, |     CONF_LATITUDE, | ||||||
|     CONF_LONGITUDE, |     CONF_LONGITUDE, | ||||||
|  |     CONF_PLATFORM, | ||||||
|     CONF_SPEED, |     CONF_SPEED, | ||||||
|     DEVICE_CLASS_SIGNAL_STRENGTH, |     DEVICE_CLASS_SIGNAL_STRENGTH, | ||||||
|     ENTITY_CATEGORY_DIAGNOSTIC, |     ENTITY_CATEGORY_DIAGNOSTIC, | ||||||
| @@ -20,7 +21,7 @@ from esphome.const import ( | |||||||
| ) | ) | ||||||
| import esphome.final_validate as fv | import esphome.final_validate as fv | ||||||
|  |  | ||||||
| from .. import CONF_ENABLE_GNSS, CONF_MODEM, final_validate_platform | from .. import CONF_MODEM, final_validate_platform, modem_ns, switch | ||||||
|  |  | ||||||
| CODEOWNERS = ["@oarcher"] | CODEOWNERS = ["@oarcher"] | ||||||
|  |  | ||||||
| @@ -28,7 +29,6 @@ AUTO_LOAD = [] | |||||||
|  |  | ||||||
| DEPENDENCIES = ["modem"] | DEPENDENCIES = ["modem"] | ||||||
|  |  | ||||||
| # MULTI_CONF = True |  | ||||||
| IS_PLATFORM_COMPONENT = True | IS_PLATFORM_COMPONENT = True | ||||||
|  |  | ||||||
| CONF_BER = "ber" | CONF_BER = "ber" | ||||||
| @@ -43,14 +43,13 @@ ICON_LOCATION_UP = "mdi:map-marker-up" | |||||||
| ICON_SPEED = "mdi:speedometer" | ICON_SPEED = "mdi:speedometer" | ||||||
| ICON_SIGNAL_BAR = "mdi:signal" | ICON_SIGNAL_BAR = "mdi:signal" | ||||||
|  |  | ||||||
| modem_sensor_ns = cg.esphome_ns.namespace("modem_sensor") | ModemSensor = modem_ns.class_("ModemSensor", cg.PollingComponent) | ||||||
| ModemSensorComponent = modem_sensor_ns.class_("ModemSensor", cg.PollingComponent) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| CONFIG_SCHEMA = cv.All( | CONFIG_SCHEMA = cv.All( | ||||||
|     cv.Schema( |     cv.Schema( | ||||||
|         { |         { | ||||||
|             cv.GenerateID(): cv.declare_id(ModemSensorComponent), |             cv.GenerateID(): cv.declare_id(ModemSensor), | ||||||
|             cv.Optional(CONF_RSSI): sensor.sensor_schema( |             cv.Optional(CONF_RSSI): sensor.sensor_schema( | ||||||
|                 unit_of_measurement=UNIT_DECIBEL, |                 unit_of_measurement=UNIT_DECIBEL, | ||||||
|                 accuracy_decimals=0, |                 accuracy_decimals=0, | ||||||
| @@ -108,16 +107,19 @@ CONFIG_SCHEMA = cv.All( | |||||||
|  |  | ||||||
|  |  | ||||||
| def _final_validate_gnss(config): | def _final_validate_gnss(config): | ||||||
|     if ( |     # GNSS sensors needs GNSS switch | ||||||
|         config.get(CONF_LATITUDE, None) |     if config.get(CONF_LATITUDE, None) or config.get(CONF_LONGITUDE, None): | ||||||
|         or config.get(CONF_LONGITUDE, None) |         gnss = False | ||||||
|         or config.get(CONF_ALTITUDE, None) |         if switches := fv.full_config.get().get("switch", None): | ||||||
|     ): |             modem_switches = filter( | ||||||
|         if modem_config := fv.full_config.get().get(CONF_MODEM, None): |                 lambda x: x.get(CONF_PLATFORM, None) and x[CONF_PLATFORM] == CONF_MODEM, | ||||||
|             if not modem_config[CONF_ENABLE_GNSS]: |                 switches, | ||||||
|                 raise cv.Invalid( |  | ||||||
|                     f"Using GNSS sensors require '{CONF_ENABLE_GNSS}' to be 'true' in '{CONF_MODEM}'." |  | ||||||
|             ) |             ) | ||||||
|  |             for sw in modem_switches: | ||||||
|  |                 if switch.CONF_GNSS in sw: | ||||||
|  |                     gnss = True | ||||||
|  |         if not gnss: | ||||||
|  |             raise cv.Invalid("Using GNSS modem sensors require GNSS modem switch.") | ||||||
|     return config |     return config | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -29,7 +29,9 @@ | |||||||
|   } |   } | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace modem_sensor { | namespace modem { | ||||||
|  |  | ||||||
|  | static const char *const TAG = "modem.sensor"; | ||||||
|  |  | ||||||
| using namespace esp_modem; | using namespace esp_modem; | ||||||
|  |  | ||||||
| @@ -40,10 +42,8 @@ void ModemSensor::update() { | |||||||
|   if (modem::global_modem_component->dce && modem::global_modem_component->modem_ready()) { |   if (modem::global_modem_component->dce && modem::global_modem_component->modem_ready()) { | ||||||
|     this->update_signal_sensors_(); |     this->update_signal_sensors_(); | ||||||
|     App.feed_wdt(); |     App.feed_wdt(); | ||||||
|     if (!modem::global_modem_component->get_gnss_power_command().empty()) { |  | ||||||
|     this->update_gnss_sensors_(); |     this->update_gnss_sensors_(); | ||||||
|   } |   } | ||||||
|   } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void ModemSensor::update_signal_sensors_() { | void ModemSensor::update_signal_sensors_() { | ||||||
| @@ -90,7 +90,9 @@ std::map<std::string, std::string> get_gnssinfo_tokens(const std::string &gnss_i | |||||||
|  |  | ||||||
|   switch (parts.size()) { |   switch (parts.size()) { | ||||||
|     case 15: |     case 15: | ||||||
|       parts.push_back(""); |       parts.emplace_back(""); | ||||||
|  |       // NOLINTNEXTLINE(bugprone-branch-clone) | ||||||
|  |       // fall through | ||||||
|     case 16: |     case 16: | ||||||
|       gnss_data["mode"] = parts[0]; |       gnss_data["mode"] = parts[0]; | ||||||
|       gnss_data["sat_used_count"] = parts[1]; |       gnss_data["sat_used_count"] = parts[1]; | ||||||
| @@ -112,7 +114,9 @@ std::map<std::string, std::string> get_gnssinfo_tokens(const std::string &gnss_i | |||||||
|       break; |       break; | ||||||
|  |  | ||||||
|     case 17: |     case 17: | ||||||
|       parts.push_back(""); |       parts.emplace_back(""); | ||||||
|  |       // NOLINTNEXTLINE(bugprone-branch-clone) | ||||||
|  |       // fall through | ||||||
|     case 18: |     case 18: | ||||||
|       gnss_data["mode"] = parts[0]; |       gnss_data["mode"] = parts[0]; | ||||||
|       gnss_data["sat_used_count"] = parts[1]; |       gnss_data["sat_used_count"] = parts[1]; | ||||||
| @@ -232,7 +236,7 @@ void ModemSensor::update_gnss_sensors_() { | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| }  // namespace modem_sensor | }  // namespace modem | ||||||
| }  // namespace esphome | }  // namespace esphome | ||||||
|  |  | ||||||
| #endif  // USE_MODEM | #endif  // USE_MODEM | ||||||
|   | |||||||
| @@ -11,9 +11,7 @@ | |||||||
| #include "esphome/components/sensor/sensor.h" | #include "esphome/components/sensor/sensor.h" | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace modem_sensor { | namespace modem { | ||||||
|  |  | ||||||
| static const char *const TAG = "modem_sensor"; |  | ||||||
|  |  | ||||||
| class ModemSensor : public PollingComponent { | class ModemSensor : public PollingComponent { | ||||||
|  public: |  public: | ||||||
| @@ -49,7 +47,7 @@ class ModemSensor : public PollingComponent { | |||||||
|   void update_gnss_sensors_(); |   void update_gnss_sensors_(); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| }  // namespace modem_sensor | }  // namespace modem | ||||||
| }  // namespace esphome | }  // namespace esphome | ||||||
|  |  | ||||||
| #endif  // USE_MODEM | #endif  // USE_MODEM | ||||||
|   | |||||||
							
								
								
									
										56
									
								
								esphome/components/modem/switch/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								esphome/components/modem/switch/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | from esphome.components import switch | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome.const import DEVICE_CLASS_SWITCH | ||||||
|  | import esphome.final_validate as fv | ||||||
|  |  | ||||||
|  | from .. import CONF_MODEL, CONF_MODEM, final_validate_platform, modem_ns | ||||||
|  |  | ||||||
|  | CODEOWNERS = ["@oarcher"] | ||||||
|  |  | ||||||
|  | AUTO_LOAD = [] | ||||||
|  |  | ||||||
|  | DEPENDENCIES = ["modem"] | ||||||
|  |  | ||||||
|  | IS_PLATFORM_COMPONENT = True | ||||||
|  |  | ||||||
|  | CONF_GNSS = "gnss" | ||||||
|  | CONF_GNSS_COMMAND = "gnss_command" | ||||||
|  |  | ||||||
|  | ICON_SATELLITE = "mdi:satellite-variant" | ||||||
|  |  | ||||||
|  | GnssSwitch = modem_ns.class_("GnssSwitch", switch.Switch, cg.Component) | ||||||
|  |  | ||||||
|  | # SIM70xx doesn't support AT+CGNSSINFO, so gnss is not available | ||||||
|  | MODEM_MODELS_GNSS_COMMAND = {"SIM7600": "AT+CGPS", "SIM7670": "AT+CGNSSPWR"} | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = cv.Schema( | ||||||
|  |     { | ||||||
|  |         cv.Optional(CONF_GNSS): switch.switch_schema( | ||||||
|  |             GnssSwitch, | ||||||
|  |             block_inverted=True, | ||||||
|  |             device_class=DEVICE_CLASS_SWITCH, | ||||||
|  |             icon=ICON_SATELLITE, | ||||||
|  |         ), | ||||||
|  |     } | ||||||
|  | ).extend(cv.COMPONENT_SCHEMA) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def _final_validate_gnss(config): | ||||||
|  |     if config.get(CONF_GNSS, None): | ||||||
|  |         modem_config = fv.full_config.get().get(CONF_MODEM) | ||||||
|  |         modem_model = modem_config.get(CONF_MODEL, None) | ||||||
|  |         if modem_model not in MODEM_MODELS_GNSS_COMMAND: | ||||||
|  |             raise cv.Invalid(f"GNSS not supported for modem '{modem_model}'.") | ||||||
|  |         config[CONF_GNSS_COMMAND] = MODEM_MODELS_GNSS_COMMAND[modem_model] | ||||||
|  |     return config | ||||||
|  |  | ||||||
|  |  | ||||||
|  | FINAL_VALIDATE_SCHEMA = cv.All(final_validate_platform, _final_validate_gnss) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     if gnss_config := config.get(CONF_GNSS): | ||||||
|  |         var = await switch.new_switch(gnss_config) | ||||||
|  |         await cg.register_component(var, config) | ||||||
|  |         cg.add(var.set_command(config[CONF_GNSS_COMMAND])) | ||||||
							
								
								
									
										37
									
								
								esphome/components/modem/switch/gnns_switch.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								esphome/components/modem/switch/gnns_switch.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | |||||||
|  | #pragma once | ||||||
|  | #ifdef USE_ESP_IDF | ||||||
|  |  | ||||||
|  | #include "esphome/core/defines.h" | ||||||
|  |  | ||||||
|  | #ifdef USE_MODEM | ||||||
|  | #ifdef USE_SWITCH | ||||||
|  |  | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #include "../modem_component.h" | ||||||
|  | #include "esphome/components/switch/switch.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace modem { | ||||||
|  |  | ||||||
|  | class GnssSwitch : public switch_::Switch, public Component { | ||||||
|  |  public: | ||||||
|  |   void set_command(const std::string &command) { this->command_ = command; } | ||||||
|  |   // ========== INTERNAL METHODS ========== | ||||||
|  |   // (In most use cases you won't need these) | ||||||
|  |  | ||||||
|  |   void dump_config() override; | ||||||
|  |   void setup() override; | ||||||
|  |   void loop() override; | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   std::string command_; | ||||||
|  |   void write_state(bool state) override; | ||||||
|  |   bool modem_state_{false}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace modem | ||||||
|  | }  // namespace esphome | ||||||
|  |  | ||||||
|  | #endif  // USE_MODEM | ||||||
|  | #endif  // USE_SWITCH | ||||||
|  | #endif  // USE_ESP_IDF | ||||||
							
								
								
									
										53
									
								
								esphome/components/modem/switch/gnss_switch.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								esphome/components/modem/switch/gnss_switch.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | |||||||
|  | #ifdef USE_ESP_IDF | ||||||
|  |  | ||||||
|  | #include "esphome/core/defines.h" | ||||||
|  |  | ||||||
|  | #ifdef USE_MODEM | ||||||
|  | #ifdef USE_SWITCH | ||||||
|  |  | ||||||
|  | #include "gnns_switch.h" | ||||||
|  |  | ||||||
|  | #include "esphome/core/log.h" | ||||||
|  | #include "esphome/core/application.h" | ||||||
|  |  | ||||||
|  | #include "../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 { | ||||||
|  |  | ||||||
|  | using namespace esp_modem; | ||||||
|  |  | ||||||
|  | static const char *const TAG = "modem.switch"; | ||||||
|  |  | ||||||
|  | void GnssSwitch::dump_config() { LOG_SWITCH("", "Modem GNSS Switch", this); } | ||||||
|  |  | ||||||
|  | void GnssSwitch::setup() { this->state = this->get_initial_state_with_restore_mode().value_or(false); } | ||||||
|  |  | ||||||
|  | void GnssSwitch::loop() { | ||||||
|  |   if ((this->state != this->modem_state_) && global_modem_component->modem_ready()) { | ||||||
|  |     global_modem_component->send_at(this->command_ + (this->state ? "=1" : "=0")); | ||||||
|  |     this->modem_state_ = this->state; | ||||||
|  |     this->publish_state(this->modem_state_); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void GnssSwitch::write_state(bool state) { this->state = state; } | ||||||
|  |  | ||||||
|  | }  // namespace modem | ||||||
|  | }  // namespace esphome | ||||||
|  |  | ||||||
|  | #endif  // USE_MODEM | ||||||
|  | #endif  // USE_SWITCH | ||||||
|  | #endif  // USE_ESP_IDF | ||||||
| @@ -3,7 +3,7 @@ from esphome.components import text_sensor | |||||||
| import esphome.config_validation as cv | import esphome.config_validation as cv | ||||||
| from esphome.const import CONF_ID, DEVICE_CLASS_EMPTY | from esphome.const import CONF_ID, DEVICE_CLASS_EMPTY | ||||||
|  |  | ||||||
| from .. import final_validate_platform | from .. import final_validate_platform, modem_ns | ||||||
|  |  | ||||||
| CODEOWNERS = ["@oarcher"] | CODEOWNERS = ["@oarcher"] | ||||||
|  |  | ||||||
| @@ -11,21 +11,16 @@ AUTO_LOAD = [] | |||||||
|  |  | ||||||
| DEPENDENCIES = ["modem"] | DEPENDENCIES = ["modem"] | ||||||
|  |  | ||||||
| # MULTI_CONF = True |  | ||||||
| IS_PLATFORM_COMPONENT = True | IS_PLATFORM_COMPONENT = True | ||||||
|  |  | ||||||
| CONF_NETWORK_TYPE = "network_type" | CONF_NETWORK_TYPE = "network_type" | ||||||
|  |  | ||||||
| modem_text_sensor_ns = cg.esphome_ns.namespace("modem_text_sensor") | ModemTextSensor = modem_ns.class_("ModemTextSensor", cg.PollingComponent) | ||||||
| ModemTextSensorComponent = modem_text_sensor_ns.class_( |  | ||||||
|     "ModemTextSensor", cg.PollingComponent |  | ||||||
| ) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| CONFIG_SCHEMA = cv.All( | CONFIG_SCHEMA = cv.All( | ||||||
|     cv.Schema( |     cv.Schema( | ||||||
|         { |         { | ||||||
|             cv.GenerateID(): cv.declare_id(ModemTextSensorComponent), |             cv.GenerateID(): cv.declare_id(ModemTextSensor), | ||||||
|             cv.Optional(CONF_NETWORK_TYPE): text_sensor.text_sensor_schema( |             cv.Optional(CONF_NETWORK_TYPE): text_sensor.text_sensor_schema( | ||||||
|                 device_class=DEVICE_CLASS_EMPTY, |                 device_class=DEVICE_CLASS_EMPTY, | ||||||
|             ), |             ), | ||||||
|   | |||||||
| @@ -25,11 +25,13 @@ | |||||||
|   } |   } | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace modem_text_sensor { | namespace modem { | ||||||
|  |  | ||||||
| using namespace esp_modem; | using namespace esp_modem; | ||||||
| // using namespace esphome::modem; | // using namespace esphome::modem; | ||||||
|  |  | ||||||
|  | static const char *const TAG = "modem.text_sensor"; | ||||||
|  |  | ||||||
| void ModemTextSensor::setup() { ESP_LOGI(TAG, "Setting up Modem Sensor..."); } | void ModemTextSensor::setup() { ESP_LOGI(TAG, "Setting up Modem Sensor..."); } | ||||||
|  |  | ||||||
| void ModemTextSensor::update() { | void ModemTextSensor::update() { | ||||||
| @@ -112,7 +114,7 @@ void ModemTextSensor::update_network_type_text_sensor_() { | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| }  // namespace modem_text_sensor | }  // namespace modem | ||||||
| }  // namespace esphome | }  // namespace esphome | ||||||
|  |  | ||||||
| #endif  // USE_MODEM | #endif  // USE_MODEM | ||||||
|   | |||||||
| @@ -11,9 +11,7 @@ | |||||||
| #include "esphome/components/text_sensor/text_sensor.h" | #include "esphome/components/text_sensor/text_sensor.h" | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace modem_text_sensor { | namespace modem { | ||||||
|  |  | ||||||
| static const char *const TAG = "modem_text_sensor"; |  | ||||||
|  |  | ||||||
| class ModemTextSensor : public PollingComponent { | class ModemTextSensor : public PollingComponent { | ||||||
|  public: |  public: | ||||||
| @@ -33,7 +31,7 @@ class ModemTextSensor : public PollingComponent { | |||||||
|   void update_network_type_text_sensor_(); |   void update_network_type_text_sensor_(); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| }  // namespace modem_text_sensor | }  // namespace modem | ||||||
| }  // namespace esphome | }  // namespace esphome | ||||||
|  |  | ||||||
| #endif  // USE_MODEM | #endif  // USE_MODEM | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user