Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 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
2 changes: 2 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ omit =
homeassistant/components/image_processing/dlib_face_detect.py
homeassistant/components/image_processing/dlib_face_identify.py
homeassistant/components/image_processing/seven_segments.py
homeassistant/components/iota.py
homeassistant/components/keyboard.py
homeassistant/components/keyboard_remote.py
homeassistant/components/light/avion.py
Expand Down Expand Up @@ -549,6 +550,7 @@ omit =
homeassistant/components/sensor/imap.py
homeassistant/components/sensor/imap_email_content.py
homeassistant/components/sensor/influxdb.py
homeassistant/components/sensor/iota.py
homeassistant/components/sensor/irish_rail_transport.py
homeassistant/components/sensor/kwb.py
homeassistant/components/sensor/lacrosse.py
Expand Down
82 changes: 82 additions & 0 deletions homeassistant/components/iota.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
"""

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.

There is only a sensor. This doesn't require to include a component.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Hey, not yet. I am going to add more features to this component. Is it necessary to be a sensor only PR?

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.

No, it's the right way to create a component if there is coming a binary sensor or switch platform which can share the common stuff. Otherwise everything can be handled in the platform itself as no sharing is needed.

Support for IOTA wallets.

For more details about this component, please refer to the documentation at
https://home-assistant.io/components/iota/
"""
import logging
from datetime import timedelta

import voluptuous as vol

import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.discovery import load_platform
from homeassistant.helpers.entity import Entity

DOMAIN = 'iota'

REQUIREMENTS = ['pyota==2.0.3']

IOTA_PLATFORMS = ['sensor']

SCAN_INTERVAL = timedelta(minutes=10)

CONF_IRI = 'iri'
CONF_TESTNET = 'testnet'
CONF_WALLETS = 'wallets'
CONF_WALLET_NAME = 'name'
CONF_WALLET_SEED = 'seed'

WALLET_CONFIG = vol.Schema({
vol.Required(CONF_WALLET_NAME): cv.string,
vol.Required(CONF_WALLET_SEED): cv.string,
})

CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({
vol.Required(CONF_IRI): cv.string,
vol.Optional(CONF_TESTNET, default=False): cv.boolean,
vol.Required(CONF_WALLETS): vol.All(cv.ensure_list, [WALLET_CONFIG])
})
}, extra=vol.ALLOW_EXTRA)

_LOGGER = logging.getLogger(__name__)


def setup(hass, config):
"""Setup IOTA component."""

# Load platforms
iota_config = config[DOMAIN]
for platform in IOTA_PLATFORMS:
load_platform(hass, platform, DOMAIN, iota_config, config)

return True


class IotaDevice(Entity):
"""Representation of a IOTA device."""

def __init__(self, name, seed, iri, is_testnet=False):
"""Initialisation of the IOTA device."""
self._name = name
self._seed = seed
self.iri = iri
self.is_testnet = is_testnet

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

@property
def device_state_attributes(self):
"""Return the state attributes of the device."""
attr = {CONF_WALLET_NAME: self._name}
return attr

@property
def api(self):
"""Construct API object for interaction with the IRI node."""
from iota import Iota
return Iota(adapter=self.iri, seed=self._seed)
103 changes: 103 additions & 0 deletions homeassistant/components/sensor/iota.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
"""
Support for IOTA wallets.

For more details about this component, please refer to the documentation at
https://home-assistant.io/components/iota
"""
import logging
from datetime import timedelta

from homeassistant.components.iota import IotaDevice

_LOGGER = logging.getLogger(__name__)

DEPENDENCIES = ['iota']

SCAN_INTERVAL = timedelta(minutes=10)


def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the IOTA sensor."""
# Add sensors for wallet balance
iota_config = discovery_info
sensors = [IotaBalanceSensor(wallet, iota_config)
for wallet in iota_config['wallets']]

# Add sensor for node information
sensors.append(IotaNodeSensor(iota_config=iota_config))

add_devices(sensors)


class IotaBalanceSensor(IotaDevice):
"""Implement an IOTA sensor for displaying wallets balance."""

def __init__(self, wallet_config, iota_config):
"""Initialize the sensor."""
super().__init__(name=wallet_config['name'],
seed=wallet_config['seed'],
iri=iota_config['iri'],
is_testnet=iota_config['testnet'])
self._state = None

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

@property
def state(self):
"""Return the state of the sensor."""
return self._state

@property
def unit_of_measurement(self):
"""Return the unit of measurement."""
return 'IOTA'

def update(self):
"""Fetch new balance from IRI."""
self._state = self.api.get_inputs()['totalBalance']


class IotaNodeSensor(IotaDevice):

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.

I assume that this should be a binary sensor. A node can be offline or online.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Nope, a node can have multiple attributes, which are changing over time (https://iota.readme.io/v1.2.0/reference#getnodeinfo)

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.

Attributes and state are not the same. A binary sensor can have attributes as well. If a node is always present then it's doesn't make sense.

There are a dozen values available from getNodeInfo. Those details should be exposed as attributes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Information about the node is part of the attributes of the node sensor and should be part of the wallet.

"""Implement an IOTA sensor for displaying attributes of node."""

def __init__(self, iota_config):
"""Initialize the sensor."""
super().__init__(name='Node Info', seed=None, iri=iota_config['iri'],
is_testnet=iota_config['testnet'])
self._state = None
self._attr = {}

@property
def name(self):
"""Return the name of the sensor."""
return 'IOTA Node'

@property
def state(self):
"""Return the state of the sensor."""
return self._state

@property
def device_state_attributes(self):
"""Return the state attributes of the device."""
return self._attr

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.

At the moment this will stay empty.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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.

Missed that line.


@property
def unit_of_measurement(self):
"""Return the unit of measurement."""
return ''

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 not a valid unit of measurement.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

removed it


def update(self):
"""Fetch new attribures IRI node."""
node_info = self.api.get_node_info()
self._state = node_info.get('appVersion')

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.

How is it useful to know the appVersion of a node as state? Will that change on a regular base? If not then it's just another attribute.

@jinnerbichler jinnerbichler Jan 15, 2018

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The value of appVersion tells if the version of the node is up-to-date. Yes, the version of the node changes almost every other week.

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.

It would still require an additional part because it only shows the version and not if the node is up-to-date.


# convert values to raw string formats
self._attr = {k: str(v) for k, v in node_info.items()}

# add values of iri config
self._attr['url'] = self.iri
self._attr['testnet'] = self.is_testnet

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.

No need to update this as it will never change. Set it when you initialize the sensor.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

3 changes: 3 additions & 0 deletions requirements_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -811,6 +811,9 @@ pynut2==2.1.2
# homeassistant.components.binary_sensor.nx584
pynx584==0.4

# homeassistant.components.iota
pyota==2.0.3

# homeassistant.components.sensor.otp
pyotp==2.2.6

Expand Down