Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make scan interval user configurable #15

Merged
merged 5 commits into from
Jun 12, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
6 changes: 5 additions & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,14 @@
"files.eol": "\n",
"editor.tabSize": 4,
"terminal.integrated.shell.linux": "/bin/bash",
"python.pythonPath": "/usr/bin/python3",
"python.pythonPath": "/usr/local/python/bin/python",
"python.analysis.autoSearchPaths": false,
"python.linting.pylintEnabled": true,
"python.linting.enabled": true,
"python.linting.pylintArgs": [
"--disable",
"import-error"
],
"python.formatting.provider": "black",
"editor.formatOnPaste": false,
"editor.formatOnSave": true,
Expand Down
22 changes: 14 additions & 8 deletions custom_components/kamstrup_403/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import serial

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_PORT
from homeassistant.const import CONF_PORT, CONF_SCAN_INTERVAL
from homeassistant.core import Config, HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers.aiohttp_client import async_get_clientsession
Expand All @@ -20,14 +20,13 @@

from .const import (
DEFAULT_BAUDRATE,
DEFAULT_SCAN_INTERVAL,
DEFAULT_TIMEOUT,
DOMAIN,
PLATFORMS,
SENSORS,
)

SCAN_INTERVAL = timedelta(seconds=60)

_LOGGER: logging.Logger = logging.getLogger(__package__)


Expand All @@ -42,9 +41,14 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
hass.data.setdefault(DOMAIN, {})

port = entry.data.get(CONF_PORT)
scan_interval_seconds = entry.options.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL)
scan_interval = timedelta(seconds=scan_interval_seconds)

client = Kamstrup(port, DEFAULT_BAUDRATE, DEFAULT_TIMEOUT)

coordinator = KamstrupUpdateCoordinator(hass, client=client)
coordinator = KamstrupUpdateCoordinator(
hass, client=client, scan_interval=scan_interval
)
await coordinator.async_refresh()

if not coordinator.last_update_success:
Expand All @@ -66,24 +70,26 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
class KamstrupUpdateCoordinator(DataUpdateCoordinator):
"""Class to manage fetching data from the Kamstrup serial reader."""

def __init__(self, hass: HomeAssistant, client: Kamstrup) -> None:
def __init__(
self, hass: HomeAssistant, client: Kamstrup, scan_interval: int
) -> None:
"""Initialize."""
self.kamstrup = client
self.platforms = []

super().__init__(hass, _LOGGER, name=DOMAIN, update_interval=SCAN_INTERVAL)
super().__init__(hass, _LOGGER, name=DOMAIN, update_interval=scan_interval)

async def _async_update_data(self):
"""Update data via library."""
_LOGGER.debug('KamstrupUpdateCoordinator: _async_update_data start')
_LOGGER.debug("KamstrupUpdateCoordinator: _async_update_data start")

data = {}
for key in SENSORS:
try:
value, unit = self.kamstrup.readvar(SENSORS[key]["command"])
data[SENSORS[key]["command"]] = {"value": value, "unit": unit}
except (serial.SerialException):
_LOGGER.error('Device disconnected or multiple access on port?')
_LOGGER.error("Device disconnected or multiple access on port?")
return data


Expand Down
13 changes: 8 additions & 5 deletions custom_components/kamstrup_403/config_flow.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
"""Adds config flow for Kamstrup 403."""
from homeassistant import config_entries
from homeassistant.const import CONF_PORT
from homeassistant.const import CONF_PORT, CONF_SCAN_INTERVAL
from homeassistant.core import callback
from homeassistant.helpers.aiohttp_client import async_create_clientsession
import voluptuous as vol
import serial

from .const import (
DEFAULT_BAUDRATE,
DEFAULT_SCAN_INTERVAL,
DEFAULT_TIMEOUT,
DOMAIN,
PLATFORMS,
)


Expand Down Expand Up @@ -98,8 +97,12 @@ async def async_step_user(self, user_input=None):
step_id="user",
data_schema=vol.Schema(
{
vol.Required(x, default=self.options.get(x, True)): bool
for x in sorted(PLATFORMS)
vol.Optional(
CONF_SCAN_INTERVAL,
default=self.config_entry.options.get(
CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL
),
): vol.All(vol.Coerce(int), vol.Range(min=1, max=86400)),
}
),
)
Expand Down
21 changes: 10 additions & 11 deletions custom_components/kamstrup_403/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,23 @@
DEVICE_CLASS_TEMPERATURE,
)
from homeassistant.components.sensor import (
STATE_CLASS_MEASUREMENT,
ATTR_STATE_CLASS,
STATE_CLASS_MEASUREMENT,
SensorStateClass,
)

# Todo, import next two from: homeassistant.sensor import SensorStateClass
TOTAL_INCREASING = "total_increasing"

# Base component constants
NAME = "Kamstrup 403"
DOMAIN = "kamstrup_403"
MODEL = "403"
MANUFACTURER = "Kamstrup"
ATTRIBUTION = "Data provided by Kamstrup 403 meter"

# Defaults
DEFAULT_BAUDRATE = 1200
DEFAULT_SCAN_INTERVAL = 60
DEFAULT_TIMEOUT = 2.0

# Platforms
SENSOR = "sensor"
PLATFORMS = [SENSOR]
Expand All @@ -35,7 +38,7 @@
# "attributes": [
# {
# "name": ATTR_STATE_CLASS,
# "value": TOTAL_INCREASING,
# "value": SensorStateClass.TOTAL_INCREASING,
# },
# ],
},
Expand Down Expand Up @@ -106,7 +109,7 @@
"attributes": [
{
"name": ATTR_STATE_CLASS,
"value": TOTAL_INCREASING,
"value": SensorStateClass.TOTAL_INCREASING,
},
],
},
Expand Down Expand Up @@ -310,12 +313,8 @@
"attributes": [
{
"name": ATTR_STATE_CLASS,
"value": TOTAL_INCREASING,
"value": SensorStateClass.TOTAL_INCREASING,
},
],
},
}

# Defaults
DEFAULT_BAUDRATE = 1200
DEFAULT_TIMEOUT = 2.0
4 changes: 1 addition & 3 deletions custom_components/kamstrup_403/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@
"step": {
"user": {
"data": {
"binary_sensor": "Binary sensor enabled",
"sensor": "Sensor enabled",
"switch": "Switch enabled"
"scan_interval": "Scan Interval (seconds)"
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion custom_components/kamstrup_403/translations/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"step": {
"user": {
"data": {
"sensor": "Sensor ingeschakeld"
"scan_interval": "Scaninterval (seconden)"
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion tests/const.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Constants for kamstrup_403 tests."""
from homeassistant.const import CONF_PORT
from homeassistant.const import CONF_PORT, CONF_SCAN_INTERVAL

# Mock config data to be used across multiple tests
MOCK_CONFIG = {CONF_PORT: "/dev/ttyUSB0"}
MOCK_UPDATE_CONFIG = {CONF_SCAN_INTERVAL: 120}
14 changes: 5 additions & 9 deletions tests/test_config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,13 @@
from unittest.mock import patch

from homeassistant import config_entries, data_entry_flow
from homeassistant.const import CONF_PORT
from homeassistant.const import CONF_PORT, CONF_SCAN_INTERVAL
import pytest
from pytest_homeassistant_custom_component.common import MockConfigEntry

from custom_components.kamstrup_403.const import (
DOMAIN,
PLATFORMS,
SENSOR,
)
from custom_components.kamstrup_403.const import DOMAIN, SENSOR

from .const import MOCK_CONFIG
from .const import MOCK_CONFIG, MOCK_UPDATE_CONFIG

# This fixture bypasses the actual setup of the integration
# since we only want to test the config flow. We test the
Expand Down Expand Up @@ -96,12 +92,12 @@ async def test_options_flow(hass):
# Enter some fake data into the form
result = await hass.config_entries.options.async_configure(
result["flow_id"],
user_input={platform: platform != SENSOR for platform in PLATFORMS},
user_input=MOCK_UPDATE_CONFIG,
)

# Verify that the flow finishes
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result["title"] == "/dev/ttyUSB0"

# Verify that the options were updated
assert entry.options == {SENSOR: False}
assert entry.options == MOCK_UPDATE_CONFIG