From 5baed6acfb34315f4a19a704b9505f107e345efa Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Sat, 13 Aug 2016 19:37:12 +0200 Subject: [PATCH] Add support for GPSD (#2254) * Add support for GPSD * Add gpsd.py * Check if socket is open * Fix pylint issue * Rename file to be a sensor * Update for being a sensor * Rework for being a sensor --- .coveragerc | 2 + homeassistant/components/sensor/gpsd.py | 111 ++++++++++++++++++++++++ requirements_all.txt | 3 + 3 files changed, 116 insertions(+) create mode 100644 homeassistant/components/sensor/gpsd.py diff --git a/.coveragerc b/.coveragerc index 08a3862d0e7..f8aa6ce1549 100644 --- a/.coveragerc +++ b/.coveragerc @@ -130,6 +130,7 @@ omit = homeassistant/components/foursquare.py homeassistant/components/garage_door/wink.py homeassistant/components/garage_door/rpi_gpio.py + homeassistant/components/gpsd.py homeassistant/components/hdmi_cec.py homeassistant/components/ifttt.py homeassistant/components/joaoapps_join.py @@ -203,6 +204,7 @@ omit = homeassistant/components/sensor/forecast.py homeassistant/components/sensor/glances.py homeassistant/components/sensor/google_travel_time.py + homeassistant/components/sensor/gpsd.py homeassistant/components/sensor/gtfs.py homeassistant/components/sensor/imap.py homeassistant/components/sensor/lastfm.py diff --git a/homeassistant/components/sensor/gpsd.py b/homeassistant/components/sensor/gpsd.py new file mode 100644 index 00000000000..a466ff32f7d --- /dev/null +++ b/homeassistant/components/sensor/gpsd.py @@ -0,0 +1,111 @@ +""" +Support for GPSD. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/sensor.gpsd/ +""" +import logging + +import voluptuous as vol + +from homeassistant.helpers.entity import Entity +import homeassistant.helpers.config_validation as cv +from homeassistant.const import (ATTR_LATITUDE, ATTR_LONGITUDE, STATE_UNKNOWN, + CONF_HOST, CONF_PORT, CONF_PLATFORM, + CONF_NAME) + +REQUIREMENTS = ['gps3==0.33.2'] + +DEFAULT_NAME = 'GPS' +DEFAULT_HOST = 'localhost' +DEFAULT_PORT = 2947 + +ATTR_GPS_TIME = 'gps_time' +ATTR_ELEVATION = 'elevation' +ATTR_SPEED = 'speed' +ATTR_CLIMB = 'climb' +ATTR_MODE = 'mode' + +PLATFORM_SCHEMA = vol.Schema({ + vol.Required(CONF_PLATFORM): 'gpsd', + vol.Optional(CONF_NAME): cv.string, + vol.Optional(CONF_HOST): cv.string, + vol.Optional(CONF_PORT): cv.string, +}) + +_LOGGER = logging.getLogger(__name__) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Setup the GPSD component.""" + name = config.get(CONF_NAME, DEFAULT_NAME) + host = config.get(CONF_HOST, DEFAULT_HOST) + port = config.get(CONF_PORT, DEFAULT_PORT) + + # Will hopefully be possible with the next gps3 update + # https://github.com/wadda/gps3/issues/11 + # from gps3 import gps3 + # try: + # gpsd_socket = gps3.GPSDSocket() + # gpsd_socket.connect(host=host, port=port) + # except GPSError: + # _LOGGER.warning('Not able to connect to GPSD') + # return False + import socket + + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + sock.connect((host, port)) + sock.shutdown(2) + _LOGGER.debug('Connection to GPSD possible') + except socket.error: + _LOGGER.error('Not able to connect to GPSD') + return False + + add_devices([GpsdSensor(hass, name, host, port)]) + + +class GpsdSensor(Entity): + """Representation of a GPS receiver available via GPSD.""" + + def __init__(self, hass, name, host, port): + """Initialize the GPSD sensor.""" + from gps3.agps3threaded import AGPS3mechanism + + self.hass = hass + self._name = name + self._host = host + self._port = port + + self.agps_thread = AGPS3mechanism() + self.agps_thread.stream_data(host=self._host, port=self._port) + self.agps_thread.run_thread() + + @property + def name(self): + """Return the name.""" + return self._name + + # pylint: disable=no-member + @property + def state(self): + """Return the state of GPSD.""" + if self.agps_thread.data_stream.mode == 3: + return "3D Fix" + elif self.agps_thread.data_stream.mode == 2: + return "2D Fix" + else: + return STATE_UNKNOWN + + @property + def state_attributes(self): + """Return the state attributes of the GPS.""" + return { + ATTR_LATITUDE: self.agps_thread.data_stream.lat, + ATTR_LONGITUDE: self.agps_thread.data_stream.lon, + ATTR_ELEVATION: self.agps_thread.data_stream.alt, + ATTR_GPS_TIME: self.agps_thread.data_stream.time, + ATTR_SPEED: self.agps_thread.data_stream.speed, + ATTR_CLIMB: self.agps_thread.data_stream.climb, + ATTR_MODE: self.agps_thread.data_stream.mode, + } diff --git a/requirements_all.txt b/requirements_all.txt index a7e924bd6cc..e2be50c8f4d 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -88,6 +88,9 @@ gntp==1.0.3 # homeassistant.components.sensor.google_travel_time googlemaps==2.4.4 +# homeassistant.components.sensor.gpsd +gps3==0.33.2 + # homeassistant.components.camera.ffmpeg ha-ffmpeg==0.4