mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Update Fitbit sensor (icons, formatting, client update) (#9031)
* Update fitbit.py Add variable icon for battery status, clean up formatting for resource names and values * Update fitbit.py and requirements_all.txt Fix PR comments and update client * Update fitbit.py Add dict map for battery levels and use icon util
This commit is contained in:
parent
d153ee0b9f
commit
c059dfdb67
@ -17,9 +17,10 @@ from homeassistant.components.http import HomeAssistantView
|
|||||||
from homeassistant.components.sensor import PLATFORM_SCHEMA
|
from homeassistant.components.sensor import PLATFORM_SCHEMA
|
||||||
from homeassistant.const import ATTR_ATTRIBUTION
|
from homeassistant.const import ATTR_ATTRIBUTION
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
|
from homeassistant.util.icon import icon_for_battery_level
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
|
||||||
REQUIREMENTS = ['fitbit==0.2.3']
|
REQUIREMENTS = ['fitbit==0.3.0']
|
||||||
|
|
||||||
_CONFIGURING = {}
|
_CONFIGURING = {}
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
@ -31,6 +32,7 @@ ATTR_CLIENT_SECRET = 'client_secret'
|
|||||||
ATTR_LAST_SAVED_AT = 'last_saved_at'
|
ATTR_LAST_SAVED_AT = 'last_saved_at'
|
||||||
|
|
||||||
CONF_MONITORED_RESOURCES = 'monitored_resources'
|
CONF_MONITORED_RESOURCES = 'monitored_resources'
|
||||||
|
CONF_CLOCK_FORMAT = 'clock_format'
|
||||||
CONF_ATTRIBUTION = 'Data provided by Fitbit.com'
|
CONF_ATTRIBUTION = 'Data provided by Fitbit.com'
|
||||||
|
|
||||||
DEPENDENCIES = ['http']
|
DEPENDENCIES = ['http']
|
||||||
@ -48,40 +50,50 @@ DEFAULT_CONFIG = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FITBIT_RESOURCES_LIST = {
|
FITBIT_RESOURCES_LIST = {
|
||||||
'activities/activityCalories': 'cal',
|
'activities/activityCalories': ['Activity Calories', 'cal', 'fire'],
|
||||||
'activities/calories': 'cal',
|
'activities/calories': ['Calories', 'cal', 'fire'],
|
||||||
'activities/caloriesBMR': 'cal',
|
'activities/caloriesBMR': ['Calories BMR', 'cal', 'fire'],
|
||||||
'activities/distance': '',
|
'activities/distance': ['Distance', '', 'map-marker'],
|
||||||
'activities/elevation': '',
|
'activities/elevation': ['Elevation', '', 'walk'],
|
||||||
'activities/floors': 'floors',
|
'activities/floors': ['Floors', 'floors', 'walk'],
|
||||||
'activities/heart': 'bpm',
|
'activities/heart': ['Resting Heart Rate', 'bpm', 'heart-pulse'],
|
||||||
'activities/minutesFairlyActive': 'minutes',
|
'activities/minutesFairlyActive':
|
||||||
'activities/minutesLightlyActive': 'minutes',
|
['Minutes Fairly Active', 'minutes', 'walk'],
|
||||||
'activities/minutesSedentary': 'minutes',
|
'activities/minutesLightlyActive':
|
||||||
'activities/minutesVeryActive': 'minutes',
|
['Minutes Lightly Active', 'minutes', 'walk'],
|
||||||
'activities/steps': 'steps',
|
'activities/minutesSedentary':
|
||||||
'activities/tracker/activityCalories': 'cal',
|
['Minutes Sedentary', 'minutes', 'seat-recline-normal'],
|
||||||
'activities/tracker/calories': 'cal',
|
'activities/minutesVeryActive': ['Minutes Very Active', 'minutes', 'run'],
|
||||||
'activities/tracker/distance': '',
|
'activities/steps': ['Steps', 'steps', 'walk'],
|
||||||
'activities/tracker/elevation': '',
|
'activities/tracker/activityCalories':
|
||||||
'activities/tracker/floors': 'floors',
|
['Tracker Activity Calories', 'cal', 'fire'],
|
||||||
'activities/tracker/minutesFairlyActive': 'minutes',
|
'activities/tracker/calories': ['Tracker Calories', 'cal', 'fire'],
|
||||||
'activities/tracker/minutesLightlyActive': 'minutes',
|
'activities/tracker/distance': ['Tracker Distance', '', 'map-marker'],
|
||||||
'activities/tracker/minutesSedentary': 'minutes',
|
'activities/tracker/elevation': ['Tracker Elevation', '', 'walk'],
|
||||||
'activities/tracker/minutesVeryActive': 'minutes',
|
'activities/tracker/floors': ['Tracker Floors', 'floors', 'walk'],
|
||||||
'activities/tracker/steps': 'steps',
|
'activities/tracker/minutesFairlyActive':
|
||||||
'body/bmi': 'BMI',
|
['Tracker Minutes Fairly Active', 'minutes', 'walk'],
|
||||||
'body/fat': '%',
|
'activities/tracker/minutesLightlyActive':
|
||||||
'devices/battery': 'level',
|
['Tracker Minutes Lightly Active', 'minutes', 'walk'],
|
||||||
'sleep/awakeningsCount': 'times awaken',
|
'activities/tracker/minutesSedentary':
|
||||||
'sleep/efficiency': '%',
|
['Tracker Minutes Sedentary', 'minutes', 'seat-recline-normal'],
|
||||||
'sleep/minutesAfterWakeup': 'minutes',
|
'activities/tracker/minutesVeryActive':
|
||||||
'sleep/minutesAsleep': 'minutes',
|
['Tracker Minutes Very Active', 'minutes', 'run'],
|
||||||
'sleep/minutesAwake': 'minutes',
|
'activities/tracker/steps': ['Tracker Steps', 'steps', 'walk'],
|
||||||
'sleep/minutesToFallAsleep': 'minutes',
|
'body/bmi': ['BMI', 'BMI', 'human'],
|
||||||
'sleep/startTime': 'start time',
|
'body/fat': ['Body Fat', '%', 'human'],
|
||||||
'sleep/timeInBed': 'time in bed',
|
'body/weight': ['Weight', '', 'human'],
|
||||||
'body/weight': ''
|
'devices/battery': ['Battery', None, None],
|
||||||
|
'sleep/awakeningsCount':
|
||||||
|
['Awakenings Count', 'times awaken', 'sleep'],
|
||||||
|
'sleep/efficiency': ['Sleep Efficiency', '%', 'sleep'],
|
||||||
|
'sleep/minutesAfterWakeup': ['Minutes After Wakeup', 'minutes', 'sleep'],
|
||||||
|
'sleep/minutesAsleep': ['Sleep Minutes Asleep', 'minutes', 'sleep'],
|
||||||
|
'sleep/minutesAwake': ['Sleep Minutes Awake', 'minutes', 'sleep'],
|
||||||
|
'sleep/minutesToFallAsleep':
|
||||||
|
['Sleep Minutes to Fall Asleep', 'minutes', 'sleep'],
|
||||||
|
'sleep/startTime': ['Sleep Start Time', None, 'clock'],
|
||||||
|
'sleep/timeInBed': ['Sleep Time in Bed', 'minutes', 'hotel']
|
||||||
}
|
}
|
||||||
|
|
||||||
FITBIT_MEASUREMENTS = {
|
FITBIT_MEASUREMENTS = {
|
||||||
@ -120,9 +132,18 @@ FITBIT_MEASUREMENTS = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BATTERY_LEVELS = {
|
||||||
|
'High': 100,
|
||||||
|
'Medium': 50,
|
||||||
|
'Low': 20,
|
||||||
|
'Empty': 0
|
||||||
|
}
|
||||||
|
|
||||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||||
vol.Optional(CONF_MONITORED_RESOURCES, default=FITBIT_DEFAULT_RESOURCES):
|
vol.Optional(CONF_MONITORED_RESOURCES, default=FITBIT_DEFAULT_RESOURCES):
|
||||||
vol.All(cv.ensure_list, [vol.In(FITBIT_RESOURCES_LIST)]),
|
vol.All(cv.ensure_list, [vol.In(FITBIT_RESOURCES_LIST)]),
|
||||||
|
vol.Optional(CONF_CLOCK_FORMAT, default='24H'):
|
||||||
|
vol.In(['12H', '24H'])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@ -257,6 +278,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
|
|||||||
|
|
||||||
dev = []
|
dev = []
|
||||||
registered_devs = authd_client.get_devices()
|
registered_devs = authd_client.get_devices()
|
||||||
|
clock_format = config.get(CONF_CLOCK_FORMAT)
|
||||||
for resource in config.get(CONF_MONITORED_RESOURCES):
|
for resource in config.get(CONF_MONITORED_RESOURCES):
|
||||||
|
|
||||||
# monitor battery for all linked FitBit devices
|
# monitor battery for all linked FitBit devices
|
||||||
@ -264,11 +286,11 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
|
|||||||
for dev_extra in registered_devs:
|
for dev_extra in registered_devs:
|
||||||
dev.append(FitbitSensor(
|
dev.append(FitbitSensor(
|
||||||
authd_client, config_path, resource,
|
authd_client, config_path, resource,
|
||||||
hass.config.units.is_metric, dev_extra))
|
hass.config.units.is_metric, clock_format, dev_extra))
|
||||||
else:
|
else:
|
||||||
dev.append(FitbitSensor(
|
dev.append(FitbitSensor(
|
||||||
authd_client, config_path, resource,
|
authd_client, config_path, resource,
|
||||||
hass.config.units.is_metric))
|
hass.config.units.is_metric, clock_format))
|
||||||
add_devices(dev, True)
|
add_devices(dev, True)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -361,34 +383,24 @@ class FitbitSensor(Entity):
|
|||||||
"""Implementation of a Fitbit sensor."""
|
"""Implementation of a Fitbit sensor."""
|
||||||
|
|
||||||
def __init__(self, client, config_path, resource_type,
|
def __init__(self, client, config_path, resource_type,
|
||||||
is_metric, extra=None):
|
is_metric, clock_format, extra=None):
|
||||||
"""Initialize the Fitbit sensor."""
|
"""Initialize the Fitbit sensor."""
|
||||||
self.client = client
|
self.client = client
|
||||||
self.config_path = config_path
|
self.config_path = config_path
|
||||||
self.resource_type = resource_type
|
self.resource_type = resource_type
|
||||||
|
self.is_metric = is_metric
|
||||||
|
self.clock_format = clock_format
|
||||||
self.extra = extra
|
self.extra = extra
|
||||||
pretty_resource = self.resource_type.replace('activities/', '')
|
self._name = FITBIT_RESOURCES_LIST[self.resource_type][0]
|
||||||
pretty_resource = pretty_resource.replace('/', ' ')
|
|
||||||
pretty_resource = pretty_resource.title()
|
|
||||||
if pretty_resource == 'Body Bmi':
|
|
||||||
pretty_resource = 'BMI'
|
|
||||||
elif pretty_resource == 'Heart':
|
|
||||||
pretty_resource = 'Resting Heart Rate'
|
|
||||||
elif pretty_resource == 'Devices Battery':
|
|
||||||
if self.extra:
|
if self.extra:
|
||||||
pretty_resource = \
|
self._name = '{0} Battery'.format(self.extra.get('deviceVersion'))
|
||||||
'{0} Battery'.format(self.extra.get('deviceVersion'))
|
unit_type = FITBIT_RESOURCES_LIST[self.resource_type][1]
|
||||||
else:
|
|
||||||
pretty_resource = 'Battery'
|
|
||||||
|
|
||||||
self._name = pretty_resource
|
|
||||||
unit_type = FITBIT_RESOURCES_LIST[self.resource_type]
|
|
||||||
if unit_type == "":
|
if unit_type == "":
|
||||||
split_resource = self.resource_type.split('/')
|
split_resource = self.resource_type.split('/')
|
||||||
try:
|
try:
|
||||||
measurement_system = FITBIT_MEASUREMENTS[self.client.system]
|
measurement_system = FITBIT_MEASUREMENTS[self.client.system]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
if is_metric:
|
if self.is_metric:
|
||||||
measurement_system = FITBIT_MEASUREMENTS['metric']
|
measurement_system = FITBIT_MEASUREMENTS['metric']
|
||||||
else:
|
else:
|
||||||
measurement_system = FITBIT_MEASUREMENTS['en_US']
|
measurement_system = FITBIT_MEASUREMENTS['en_US']
|
||||||
@ -414,9 +426,11 @@ class FitbitSensor(Entity):
|
|||||||
@property
|
@property
|
||||||
def icon(self):
|
def icon(self):
|
||||||
"""Icon to use in the frontend, if any."""
|
"""Icon to use in the frontend, if any."""
|
||||||
if self.resource_type == 'devices/battery':
|
if self.resource_type == 'devices/battery' and self.extra:
|
||||||
return 'mdi:battery-50'
|
battery_level = BATTERY_LEVELS[self.extra.get('battery')]
|
||||||
return 'mdi:walk'
|
return icon_for_battery_level(battery_level=battery_level,
|
||||||
|
charging=None)
|
||||||
|
return 'mdi:{}'.format(FITBIT_RESOURCES_LIST[self.resource_type][2])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_state_attributes(self):
|
def device_state_attributes(self):
|
||||||
@ -438,7 +452,40 @@ class FitbitSensor(Entity):
|
|||||||
else:
|
else:
|
||||||
container = self.resource_type.replace("/", "-")
|
container = self.resource_type.replace("/", "-")
|
||||||
response = self.client.time_series(self.resource_type, period='7d')
|
response = self.client.time_series(self.resource_type, period='7d')
|
||||||
self._state = response[container][-1].get('value')
|
raw_state = response[container][-1].get('value')
|
||||||
|
if self.resource_type == 'activities/distance':
|
||||||
|
self._state = format(float(raw_state), '.2f')
|
||||||
|
elif self.resource_type == 'activities/tracker/distance':
|
||||||
|
self._state = format(float(raw_state), '.2f')
|
||||||
|
elif self.resource_type == 'body/bmi':
|
||||||
|
self._state = format(float(raw_state), '.1f')
|
||||||
|
elif self.resource_type == 'body/fat':
|
||||||
|
self._state = format(float(raw_state), '.1f')
|
||||||
|
elif self.resource_type == 'body/weight':
|
||||||
|
self._state = format(float(raw_state), '.1f')
|
||||||
|
elif self.resource_type == 'sleep/startTime':
|
||||||
|
if raw_state == '':
|
||||||
|
self._state = '-'
|
||||||
|
elif self.clock_format == '12H':
|
||||||
|
hours, minutes = raw_state.split(':')
|
||||||
|
hours, minutes = int(hours), int(minutes)
|
||||||
|
setting = 'AM'
|
||||||
|
if hours > 12:
|
||||||
|
setting = 'PM'
|
||||||
|
hours -= 12
|
||||||
|
elif hours == 0:
|
||||||
|
hours = 12
|
||||||
|
self._state = '{}:{} {}'.format(hours, minutes, setting)
|
||||||
|
else:
|
||||||
|
self._state = raw_state
|
||||||
|
else:
|
||||||
|
if self.is_metric:
|
||||||
|
self._state = raw_state
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
self._state = '{0:,}'.format(int(raw_state))
|
||||||
|
except TypeError:
|
||||||
|
self._state = raw_state
|
||||||
|
|
||||||
if self.resource_type == 'activities/heart':
|
if self.resource_type == 'activities/heart':
|
||||||
self._state = response[container][-1]. \
|
self._state = response[container][-1]. \
|
||||||
|
@ -219,7 +219,7 @@ fedexdeliverymanager==1.0.3
|
|||||||
feedparser==5.2.1
|
feedparser==5.2.1
|
||||||
|
|
||||||
# homeassistant.components.sensor.fitbit
|
# homeassistant.components.sensor.fitbit
|
||||||
fitbit==0.2.3
|
fitbit==0.3.0
|
||||||
|
|
||||||
# homeassistant.components.sensor.fixer
|
# homeassistant.components.sensor.fixer
|
||||||
fixerio==0.1.1
|
fixerio==0.1.1
|
||||||
|
Loading…
x
Reference in New Issue
Block a user