Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ omit =
homeassistant/components/isy994.py
homeassistant/components/*/isy994.py

homeassistant/components/juicenet.py
homeassistant/components/*/juicenet.py

homeassistant/components/kira.py
homeassistant/components/*/kira.py

Expand Down
104 changes: 104 additions & 0 deletions homeassistant/components/juicenet.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
"""
Support for Juicenet cloud.

For more details about this component, please refer to the documentation at
https://home-assistant.io/components/juicenet
"""

import logging
import time

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'time' imported but unused


import voluptuous as vol

from homeassistant.helpers import discovery
from homeassistant.const import CONF_ACCESS_TOKEN
from homeassistant.helpers.entity import Entity
import homeassistant.helpers.config_validation as cv

REQUIREMENTS = ['python-juicenet==0.0.3']

_LOGGER = logging.getLogger(__name__)

DOMAIN = 'juicenet'

SERVICE_ADD_NEW_DEVICES = 'add_new_devices'
SERVICE_REFRESH_STATES = 'refresh_state_from_juicenet'

CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({
vol.Required(CONF_ACCESS_TOKEN): cv.string
})
}, extra=vol.ALLOW_EXTRA)


def setup(hass, config):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expected 2 blank lines, found 1

"""Set up the Juicenet component."""
import pyjuicenet

hass.data[DOMAIN] = {}
hass.data[DOMAIN]['unique_ids'] = []
hass.data[DOMAIN]['entities'] = {}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're no longer using this?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above


access_token = config[DOMAIN].get(CONF_ACCESS_TOKEN)

hass.data[DOMAIN]['api'] = pyjuicenet.Api(access_token)

def force_update(call):
"""Force all devices to poll the Juicenet API."""
_LOGGER.info("Refreshing Juicenet states from API")
for entity_list in hass[DOMAIN]['entities'].values():
for entity in entity_list:
time.sleep(1)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't use sleep. Can you fetch all the data at once and then notifiy the entities with new info?

entity.schedule_update_ha_state(True)
hass.services.register(DOMAIN, SERVICE_REFRESH_STATES, force_update)

def pull_new_devices(call):
"""Pull new devices added to users Juicenet account since startup."""
_LOGGER.info("Getting new devices from Juicenet API")
discovery.load_platform(hass, 'sensor', DOMAIN, {}, config)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a very weird way of "pulling" new devices. Why can't you talk to the API directly?

hass.services.register(DOMAIN, SERVICE_ADD_NEW_DEVICES, pull_new_devices)

hass.data[DOMAIN]['entities']['sensor'] = []
discovery.load_platform(hass, 'sensor', DOMAIN, {}, config)

return True


class JuicenetDevice(Entity):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expected 2 blank lines, found 1

"""Represent a base Juicenet device."""

def __init__(self, device, sensor_type, hass):
"""Initialise the sensor."""
self.hass = hass
self.device = device
self.type = sensor_type
hass.data[DOMAIN]['unique_ids'].append(self.device.id())

@property
def name(self):
"""Return the name of the device."""
return self.device.name()

def update(self):
"""Update state of the device."""
self.device.update_state()

@property
def device_state_attributes(self):
"""Return the state attributes."""
attributes = {}
if self.type == 'status':

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be in a generic JuiceNet entity. This is part of an implementation.

man_dev_id = self._manufacturer_device_id
if man_dev_id:
attributes["manufacturer_device_id"] = man_dev_id
return attributes

@property
def _manufacturer_device_id(self):
"""Return the manufacturer device id."""
return self.device.id()

@property
def _token(self):
"""Return the device API token."""
return self.device.token()
125 changes: 125 additions & 0 deletions homeassistant/components/sensor/juicenet.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
"""
Support for monitoring juicenet/juicepoint/juicebox based EVSE sensors.

For more details about this platform, please refer to the documentation at
at https://home-assistant.io/components/sensor.juicenet/
"""

import asyncio

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'asyncio' imported but unused

import logging

from homeassistant.const import TEMP_CELSIUS
from homeassistant.helpers.entity import Entity
from homeassistant.components.juicenet import JuicenetDevice, DOMAIN

DEPENDENCIES = ['juicenet']
_LOGGER = logging.getLogger(__name__)

SENSOR_TYPES = {
'status': ['Charging Status', None],
'temperature': ['Temperature', TEMP_CELSIUS],
'voltage': ['Voltage', 'V'],
'amps': ['Amps', 'A'],
'watts': ['Watts', 'W'],
'charge_time': ['Charge time', 's'],
'energy_added': ['Energy added', 'Wh']
}


def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the Juicenet sensor."""
api = hass.data[DOMAIN]['api']

dev = []
for device in api.get_devices():
_id = device.id()
if _id not in hass.data[DOMAIN]['unique_ids']:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't have to do this, Home Assistant does this automatically as long as you implement the property unique_id.

for variable in SENSOR_TYPES:
dev.append(JuicenetSensorDevice(device, variable, hass))

add_devices(dev)


class JuicenetSensorDevice(JuicenetDevice, Entity):
"""Implementation of a Juicenet sensor."""

def __init__(self, device, sensor_type, hass):
"""Initialise the sensor."""
super().__init__(device, sensor_type, hass)
self._name = SENSOR_TYPES[sensor_type][0]
self._unit_of_measurement = SENSOR_TYPES[sensor_type][1]

@asyncio.coroutine
def async_added_to_hass(self):
"""Callback when entity is added to hass."""
self.hass.data[DOMAIN]['entities']['sensor'].append(self)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you appending it, is this still necessary?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above


@property
def name(self):
"""Return the name of the device."""
return '{} {}'.format(self.device.name(), self._name)

@property
def icon(self):
"""Return the icon of the sensor."""
icon = None
if self.type == 'status':
status = self.device.getStatus()
if status == 'standby':
icon = 'mdi:power-plug-off'
elif status == 'plugged':
icon = 'mdi:power-plug'
elif status == 'charging':
icon = 'mdi:battery-positive'
elif self.type == 'temperature':
icon = 'mdi:thermometer'
elif self.type == 'voltage':
icon = 'mdi:flash'
elif self.type == 'amps':
icon = 'mdi:flash'
elif self.type == 'watts':
icon = 'mdi:flash'
elif self.type == 'charge_time':
icon = 'mdi:timer'
elif self.type == 'energy_added':
icon = 'mdi:flash'
else:
icon = 'mdi:eye'

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should return None. That will cause Home Assistant to use the default sensor icon.

return icon

@property
def unit_of_measurement(self):
"""Return the unit the value is expressed in."""
return self._unit_of_measurement

@property
def state(self):
"""Return the state."""
state = None
if self.type == 'status':
state = self.device.getStatus()
elif self.type == 'temperature':
state = self.device.getTemperature()
elif self.type == 'voltage':
state = self.device.getVoltage()
elif self.type == 'amps':
state = self.device.getAmps()
elif self.type == 'watts':
state = self.device.getWatts()
elif self.type == 'charge_time':
state = self.device.getChargeTime()
elif self.type == 'energy_added':
state = self.device.getEnergyAdded()
else:
state = 'Unknown'
return state

@property
def device_state_attributes(self):
"""Return the state attributes."""
attributes = super().device_state_attributes
if self.type == 'status':
man_dev_id = self.device.id()
if man_dev_id:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

undefined name 'man_dev_id'

attributes["manufacturer_device_id"] = man_dev_id

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

undefined name 'man_dev_id'

return attributes
3 changes: 3 additions & 0 deletions requirements_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,9 @@ python-hpilo==3.9
# homeassistant.components.notify.joaoapps_join
python-join-api==0.0.2

# homeassistant.components.juicenet
python-juicenet==0.0.3

# homeassistant.components.lirc
# python-lirc==1.2.3

Expand Down