From bf1885af3f5045a43dce38339485326678fc4b44 Mon Sep 17 00:00:00 2001 From: John Coggeshall Date: Sun, 11 Apr 2021 13:15:23 -0400 Subject: [PATCH] Implementing the remainder of GPS data for the GPS component. (#1676) --- CODEOWNERS | 1 + esphome/components/gps/__init__.py | 64 +++++++++++++++++++++++++++++- esphome/components/gps/gps.cpp | 43 +++++++++++++++----- esphome/components/gps/gps.h | 27 ++++++++++++- esphome/components/sun/__init__.py | 10 +++-- esphome/const.py | 5 +++ 6 files changed, 134 insertions(+), 16 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 472e304fb0..24b4bd362d 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -38,6 +38,7 @@ esphome/components/ezo/* @ssieb esphome/components/fastled_base/* @OttoWinter esphome/components/globals/* @esphome/core esphome/components/gpio/* @esphome/core +esphome/components/gps/* @coogle esphome/components/homeassistant/* @OttoWinter esphome/components/i2c/* @esphome/core esphome/components/inkbird_ibsth1_mini/* @fkirill diff --git a/esphome/components/gps/__init__.py b/esphome/components/gps/__init__.py index 60dcc2002c..c09a49315c 100644 --- a/esphome/components/gps/__init__.py +++ b/esphome/components/gps/__init__.py @@ -1,9 +1,27 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import uart -from esphome.const import CONF_ID +from esphome.components import sensor +from esphome.const import ( + CONF_ID, + CONF_LATITUDE, + CONF_LONGITUDE, + CONF_SPEED, + CONF_COURSE, + CONF_ALTITUDE, + CONF_SATELLITES, + UNIT_DEGREES, + UNIT_KILOMETER_PER_HOUR, + UNIT_METER, + UNIT_EMPTY, + ICON_EMPTY, + DEVICE_CLASS_EMPTY, +) DEPENDENCIES = ["uart"] +AUTO_LOAD = ["sensor"] + +CODEOWNERS = ["@coogle"] gps_ns = cg.esphome_ns.namespace("gps") GPS = gps_ns.class_("GPS", cg.Component, uart.UARTDevice) @@ -15,9 +33,27 @@ CONFIG_SCHEMA = ( cv.Schema( { cv.GenerateID(): cv.declare_id(GPS), + cv.Optional(CONF_LATITUDE): sensor.sensor_schema( + UNIT_DEGREES, ICON_EMPTY, 6, DEVICE_CLASS_EMPTY + ), + cv.Optional(CONF_LONGITUDE): sensor.sensor_schema( + UNIT_DEGREES, ICON_EMPTY, 6, DEVICE_CLASS_EMPTY + ), + cv.Optional(CONF_SPEED): sensor.sensor_schema( + UNIT_KILOMETER_PER_HOUR, ICON_EMPTY, 6, DEVICE_CLASS_EMPTY + ), + cv.Optional(CONF_COURSE): sensor.sensor_schema( + UNIT_DEGREES, ICON_EMPTY, 2, DEVICE_CLASS_EMPTY + ), + cv.Optional(CONF_ALTITUDE): sensor.sensor_schema( + UNIT_METER, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY + ), + cv.Optional(CONF_SATELLITES): sensor.sensor_schema( + UNIT_EMPTY, ICON_EMPTY, 0, DEVICE_CLASS_EMPTY + ), } ) - .extend(cv.COMPONENT_SCHEMA) + .extend(cv.polling_component_schema("20s")) .extend(uart.UART_DEVICE_SCHEMA) ) @@ -27,5 +63,29 @@ def to_code(config): yield cg.register_component(var, config) yield uart.register_uart_device(var, config) + if CONF_LATITUDE in config: + sens = yield sensor.new_sensor(config[CONF_LATITUDE]) + cg.add(var.set_latitude_sensor(sens)) + + if CONF_LONGITUDE in config: + sens = yield sensor.new_sensor(config[CONF_LONGITUDE]) + cg.add(var.set_longitude_sensor(sens)) + + if CONF_SPEED in config: + sens = yield sensor.new_sensor(config[CONF_SPEED]) + cg.add(var.set_speed_sensor(sens)) + + if CONF_COURSE in config: + sens = yield sensor.new_sensor(config[CONF_COURSE]) + cg.add(var.set_course_sensor(sens)) + + if CONF_ALTITUDE in config: + sens = yield sensor.new_sensor(config[CONF_ALTITUDE]) + cg.add(var.set_altitude_sensor(sens)) + + if CONF_SATELLITES in config: + sens = yield sensor.new_sensor(config[CONF_SATELLITES]) + cg.add(var.set_satellites_sensor(sens)) + # https://platformio.org/lib/show/1655/TinyGPSPlus cg.add_library("1655", "1.0.2") # TinyGPSPlus, has name conflict diff --git a/esphome/components/gps/gps.cpp b/esphome/components/gps/gps.cpp index 26371565f3..ba0afdf7cc 100644 --- a/esphome/components/gps/gps.cpp +++ b/esphome/components/gps/gps.cpp @@ -8,34 +8,57 @@ static const char *TAG = "gps"; TinyGPSPlus &GPSListener::get_tiny_gps() { return this->parent_->get_tiny_gps(); } +void GPS::update() { + if (this->latitude_sensor_ != nullptr) + this->latitude_sensor_->publish_state(this->latitude_); + + if (this->longitude_sensor_ != nullptr) + this->longitude_sensor_->publish_state(this->longitude_); + + if (this->speed_sensor_ != nullptr) + this->speed_sensor_->publish_state(this->speed_); + + if (this->course_sensor_ != nullptr) + this->course_sensor_->publish_state(this->course_); + + if (this->altitude_sensor_ != nullptr) + this->altitude_sensor_->publish_state(this->altitude_); + + if (this->satellites_sensor_ != nullptr) + this->satellites_sensor_->publish_state(this->satellites_); +} + void GPS::loop() { while (this->available() && !this->has_time_) { if (this->tiny_gps_.encode(this->read())) { if (tiny_gps_.location.isUpdated()) { + this->latitude_ = tiny_gps_.location.lat(); + this->longitude_ = tiny_gps_.location.lng(); + ESP_LOGD(TAG, "Location:"); - ESP_LOGD(TAG, " Lat: %f", tiny_gps_.location.lat()); - ESP_LOGD(TAG, " Lon: %f", tiny_gps_.location.lng()); + ESP_LOGD(TAG, " Lat: %f", this->latitude_); + ESP_LOGD(TAG, " Lon: %f", this->longitude_); } if (tiny_gps_.speed.isUpdated()) { + this->speed_ = tiny_gps_.speed.kmph(); ESP_LOGD(TAG, "Speed:"); - ESP_LOGD(TAG, " %f km/h", tiny_gps_.speed.kmph()); + ESP_LOGD(TAG, " %f km/h", this->speed_); } if (tiny_gps_.course.isUpdated()) { + this->course_ = tiny_gps_.course.deg(); ESP_LOGD(TAG, "Course:"); - ESP_LOGD(TAG, " %f °", tiny_gps_.course.deg()); + ESP_LOGD(TAG, " %f °", this->course_); } if (tiny_gps_.altitude.isUpdated()) { + this->altitude_ = tiny_gps_.altitude.meters(); ESP_LOGD(TAG, "Altitude:"); - ESP_LOGD(TAG, " %f m", tiny_gps_.altitude.meters()); + ESP_LOGD(TAG, " %f m", this->altitude_); } if (tiny_gps_.satellites.isUpdated()) { + this->satellites_ = tiny_gps_.satellites.value(); ESP_LOGD(TAG, "Satellites:"); - ESP_LOGD(TAG, " %d", tiny_gps_.satellites.value()); - } - if (tiny_gps_.satellites.isUpdated()) { - ESP_LOGD(TAG, "HDOP:"); - ESP_LOGD(TAG, " %.2f", tiny_gps_.hdop.hdop()); + ESP_LOGD(TAG, " %d", this->satellites_); } for (auto *listener : this->listeners_) diff --git a/esphome/components/gps/gps.h b/esphome/components/gps/gps.h index 84a9248bc6..50dd476ae3 100644 --- a/esphome/components/gps/gps.h +++ b/esphome/components/gps/gps.h @@ -2,6 +2,7 @@ #include "esphome/core/component.h" #include "esphome/components/uart/uart.h" +#include "esphome/components/sensor/sensor.h" #include namespace esphome { @@ -20,17 +21,41 @@ class GPSListener { GPS *parent_; }; -class GPS : public Component, public uart::UARTDevice { +class GPS : public PollingComponent, public uart::UARTDevice { public: + void set_latitude_sensor(sensor::Sensor *latitude_sensor) { latitude_sensor_ = latitude_sensor; } + void set_longitude_sensor(sensor::Sensor *longitude_sensor) { longitude_sensor_ = longitude_sensor; } + void set_speed_sensor(sensor::Sensor *speed_sensor) { speed_sensor_ = speed_sensor; } + void set_course_sensor(sensor::Sensor *course_sensor) { course_sensor_ = course_sensor; } + void set_altitude_sensor(sensor::Sensor *altitude_sensor) { altitude_sensor_ = altitude_sensor; } + void set_satellites_sensor(sensor::Sensor *satellites_sensor) { satellites_sensor_ = satellites_sensor; } + void register_listener(GPSListener *listener) { listener->parent_ = this; this->listeners_.push_back(listener); } float get_setup_priority() const override { return setup_priority::HARDWARE; } + void loop() override; + void update() override; + TinyGPSPlus &get_tiny_gps() { return this->tiny_gps_; } protected: + float latitude_ = -1; + float longitude_ = -1; + float speed_ = -1; + float course_ = -1; + float altitude_ = -1; + int satellites_ = -1; + + sensor::Sensor *latitude_sensor_{nullptr}; + sensor::Sensor *longitude_sensor_{nullptr}; + sensor::Sensor *speed_sensor_{nullptr}; + sensor::Sensor *course_sensor_{nullptr}; + sensor::Sensor *altitude_sensor_{nullptr}; + sensor::Sensor *satellites_sensor_{nullptr}; + bool has_time_{false}; TinyGPSPlus tiny_gps_; std::vector listeners_{}; diff --git a/esphome/components/sun/__init__.py b/esphome/components/sun/__init__.py index b24d62f32f..8cc911529b 100644 --- a/esphome/components/sun/__init__.py +++ b/esphome/components/sun/__init__.py @@ -4,7 +4,13 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import automation from esphome.components import time -from esphome.const import CONF_TIME_ID, CONF_ID, CONF_TRIGGER_ID +from esphome.const import ( + CONF_TIME_ID, + CONF_ID, + CONF_TRIGGER_ID, + CONF_LATITUDE, + CONF_LONGITUDE, +) CODEOWNERS = ["@OttoWinter"] sun_ns = cg.esphome_ns.namespace("sun") @@ -16,8 +22,6 @@ SunTrigger = sun_ns.class_( SunCondition = sun_ns.class_("SunCondition", automation.Condition) CONF_SUN_ID = "sun_id" -CONF_LATITUDE = "latitude" -CONF_LONGITUDE = "longitude" CONF_ELEVATION = "elevation" CONF_ON_SUNRISE = "on_sunrise" CONF_ON_SUNSET = "on_sunset" diff --git a/esphome/const.py b/esphome/const.py index 48bab31c6c..629495bdd1 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -58,6 +58,7 @@ CONF_ACTION_ID = "action_id" CONF_ADDRESS = "address" CONF_ADDRESSABLE_LIGHT_ID = "addressable_light_id" CONF_ALPHA = "alpha" +CONF_ALTITUDE = "altitude" CONF_AND = "and" CONF_AP = "ap" CONF_ARDUINO_VERSION = "arduino_version" @@ -130,6 +131,7 @@ CONF_CONTRAST = "contrast" CONF_COOL_ACTION = "cool_action" CONF_COOL_MODE = "cool_mode" CONF_COUNT_MODE = "count_mode" +CONF_COURSE = "course" CONF_CRON = "cron" CONF_CS_PIN = "cs_pin" CONF_CSS_INCLUDE = "css_include" @@ -272,6 +274,7 @@ CONF_KEEP_ON_TIME = "keep_on_time" CONF_KEEPALIVE = "keepalive" CONF_KEY = "key" CONF_LAMBDA = "lambda" +CONF_LATITUDE = "latitude" CONF_LENGTH = "length" CONF_LEVEL = "level" CONF_LG = "lg" @@ -284,6 +287,7 @@ CONF_LOCAL = "local" CONF_LOG_TOPIC = "log_topic" CONF_LOGGER = "logger" CONF_LOGS = "logs" +CONF_LONGITUDE = "longitude" CONF_LOW = "low" CONF_LOW_VOLTAGE_REFERENCE = "low_voltage_reference" CONF_MAC_ADDRESS = "mac_address" @@ -458,6 +462,7 @@ CONF_RX_ONLY = "rx_only" CONF_RX_PIN = "rx_pin" CONF_SAFE_MODE = "safe_mode" CONF_SAMSUNG = "samsung" +CONF_SATELLITES = "satellites" CONF_SCAN = "scan" CONF_SCL = "scl" CONF_SCL_PIN = "scl_pin"