Skip to content

Commit

Permalink
Merge pull request #24 from bluecurrent/switch-changes
Browse files Browse the repository at this point in the history
Switch changes
  • Loading branch information
Floris272 authored Jul 13, 2023
2 parents 6ab19fd + 395558d commit 1b77674
Show file tree
Hide file tree
Showing 20 changed files with 157 additions and 116 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,12 @@ The following sensors are created as well, but disabled by default:
## Switch
The Blue Current integration provides the following switches:

- Operative
- Block
- Enables or disables a charge point.
- Plug and charge
- Allows you to start a session without having to scan a card.
- Public charging
- Allows other people to use your charge point.
- Linked charge cards only
- Toggles if the chargepoint is usable with unlinked charge cards.

## Button
The Blue Current integration provides the following buttons:
Expand Down
37 changes: 23 additions & 14 deletions custom_components/blue_current/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,19 @@
from typing import Any

from bluecurrent_api import Client
from bluecurrent_api.exceptions import (BlueCurrentException, InvalidApiToken,
RequestLimitReached,
WebsocketException)
from bluecurrent_api.exceptions import (
BlueCurrentException,
InvalidApiToken,
RequestLimitReached,
WebsocketError,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (CONF_API_TOKEN, EVENT_HOMEASSISTANT_STOP,
Platform)
from homeassistant.const import (
CONF_API_TOKEN,
EVENT_HOMEASSISTANT_STOP,
Platform,
ATTR_NAME,
)
from homeassistant.core import Event, HomeAssistant, ServiceCall
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
from homeassistant.helpers import entity_registry
Expand All @@ -20,6 +27,7 @@

from .const import CARD, DOMAIN, EVSE_ID, LOGGER, MODEL_TYPE

# websocket.URL = "wss://bo-acct001.bluecurrent.nl/haserver"
PLATFORMS = [Platform.SENSOR, Platform.SWITCH, Platform.BUTTON]
CHARGE_POINTS = "CHARGE_POINTS"
DATA = "data"
Expand All @@ -29,11 +37,11 @@
GRID = "GRID"
OBJECT = "object"
VALUE_TYPES = ("CH_STATUS", "CH_SETTINGS")
SETTINGS = ("PUBLIC_CHARGING", "PLUG_AND_CHARGE")
SETTINGS = ("LINKED_CHARGE_CARDS_ONLY", "PLUG_AND_CHARGE")
RESULT = "result"
ACTIVITY = "activity"
UNAVAILABLE = "unavailable"
OPERATIVE = "operative"
BLOCK = "block"
SERVICES = ("SOFT_RESET", "REBOOT", "START_SESSION", "STOP_SESSION")
SUCCESS = "success"
RESET = "reset"
Expand Down Expand Up @@ -137,7 +145,8 @@ async def handle_charge_points(data: list) -> None:
for entry in data:
evse_id = entry[EVSE_ID]
model = entry[MODEL_TYPE]
self.add_charge_point(evse_id, model)
name = entry[ATTR_NAME]
self.add_charge_point(evse_id, model, name)
await self.get_charge_point_data(evse_id)
await self.client.get_grid_status(data[0][EVSE_ID])

Expand Down Expand Up @@ -181,19 +190,19 @@ async def get_charge_point_data(self, evse_id: str) -> None:
await self.client.get_status(evse_id)
await self.client.get_settings(evse_id)

def add_charge_point(self, evse_id: str, model: str) -> None:
def add_charge_point(self, evse_id: str, model: str, name: str) -> None:
"""Add a charge point to charge_points."""
self.charge_points[evse_id] = {MODEL_TYPE: model}
self.charge_points[evse_id] = {MODEL_TYPE: model, ATTR_NAME: name}

def update_charge_point(self, evse_id: str, data: dict) -> None:
"""Update the charge point data."""

def handle_activity(data: dict) -> None:
activity = data.get(ACTIVITY)
if activity != UNAVAILABLE:
data[OPERATIVE] = True
data[BLOCK] = False
else:
data[OPERATIVE] = False
data[BLOCK] = True

if ACTIVITY in data:
handle_activity(data)
Expand Down Expand Up @@ -233,11 +242,11 @@ async def reconnect(self, event_time: datetime | None = None) -> None:
async_call_later(
self.hass, self.client.get_next_reset_delta(), self.reconnect
)
except WebsocketException:
except WebsocketError:
set_entities_unavalible(self.hass, self.config.entry_id)
async_call_later(self.hass, LARGE_DELAY, self.reconnect)

async def disconnect(self) -> None:
"""Disconnect from the websocket."""
with suppress(WebsocketException):
with suppress(WebsocketError):
await self.client.disconnect()
19 changes: 15 additions & 4 deletions custom_components/blue_current/button.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
"""Support for Blue Current buttons."""
from __future__ import annotations

from homeassistant.components.button import (ButtonEntity,
ButtonEntityDescription)
from homeassistant.components.button import (
ButtonEntity,
ButtonEntityDescription,
ButtonDeviceClass,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
Expand All @@ -13,10 +16,18 @@

BUTTONS = (
ButtonEntityDescription(
key="reset", name="Reset", icon="mdi:restart", has_entity_name=True
key="reset",
name="Reset",
icon="mdi:restart",
has_entity_name=True,
device_class=ButtonDeviceClass.RESTART,
),
ButtonEntityDescription(
key="reboot", name="Reboot", icon="mdi:restart-alert", has_entity_name=True
key="reboot",
name="Reboot",
icon="mdi:restart-alert",
has_entity_name=True,
device_class=ButtonDeviceClass.RESTART,
),
ButtonEntityDescription(
key="start_session", name="Start session", icon="mdi:play", has_entity_name=True
Expand Down
27 changes: 14 additions & 13 deletions custom_components/blue_current/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@

import voluptuous as vol
from bluecurrent_api import Client
from bluecurrent_api.exceptions import (AlreadyConnected, InvalidApiToken,
NoCardsFound, RequestLimitReached,
WebsocketException)
from bluecurrent_api.exceptions import (
AlreadyConnected,
InvalidApiToken,
NoCardsFound,
RequestLimitReached,
WebsocketError,
)
from homeassistant import config_entries
from homeassistant.const import CONF_API_TOKEN, CONF_NAME
from homeassistant.const import CONF_API_TOKEN, CONF_ID
from homeassistant.data_entry_flow import FlowResult

from .const import CARD, DOMAIN, LOGGER
Expand All @@ -37,14 +41,13 @@ async def async_step_user(
self.client = Client()
errors = {}
if user_input is not None:

api_token = user_input[CONF_API_TOKEN]
self._async_abort_entries_match({CONF_API_TOKEN: api_token})

try:
await self.client.validate_api_token(api_token)
email = await self.client.get_email()
except WebsocketException:
except WebsocketError:
errors["base"] = "cannot_connect"
except RequestLimitReached:
errors["base"] = "limit_reached"
Expand All @@ -57,7 +60,6 @@ async def async_step_user(
errors["base"] = "unknown"

if not errors:

self.entry = await self.async_set_unique_id(email)
self.input = {CONF_API_TOKEN: api_token}

Expand Down Expand Up @@ -86,7 +88,7 @@ async def async_step_card(
api_token = self.input[CONF_API_TOKEN]
try:
cards = await self.client.get_charge_cards()
except WebsocketException:
except WebsocketError:
errors["base"] = "cannot_connect"
except NoCardsFound:
errors["base"] = "no_cards_found"
Expand All @@ -99,15 +101,14 @@ async def async_step_card(
errors["base"] = "unknown"

if not errors:
card_names = [card[CONF_NAME] for card in cards]
card_schema = vol.Schema({vol.Required(CARD): vol.In(card_names)})
card_ids = [card[CONF_ID] for card in cards]
card_schema = vol.Schema({vol.Required(CARD): vol.In(card_ids)})

def check_card(card: dict) -> bool:
assert user_input is not None
return bool(card[CONF_NAME] == user_input[CARD])
# assert user_input is not None
return bool(card[CONF_ID] == user_input[CARD])

if user_input is not None:

selected_card = list(filter(check_card, cards))[0]

self.input[CARD] = selected_card["uid"]
Expand Down
14 changes: 9 additions & 5 deletions custom_components/blue_current/device_condition.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@
from __future__ import annotations

import voluptuous as vol
from homeassistant.const import (ATTR_ENTITY_ID, CONF_CONDITION,
CONF_DEVICE_ID, CONF_DOMAIN, CONF_ENTITY_ID,
CONF_TYPE)
from homeassistant.const import (
ATTR_ENTITY_ID,
CONF_CONDITION,
CONF_DEVICE_ID,
CONF_DOMAIN,
CONF_ENTITY_ID,
CONF_TYPE,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import condition
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers import device_registry
from homeassistant.helpers.config_validation import \
DEVICE_CONDITION_BASE_SCHEMA
from homeassistant.helpers.config_validation import DEVICE_CONDITION_BASE_SCHEMA
from homeassistant.helpers.typing import ConfigType, TemplateVarsType

from . import DOMAIN
Expand Down
12 changes: 8 additions & 4 deletions custom_components/blue_current/device_trigger.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@
from typing import Any

import voluptuous as vol
from homeassistant.components.device_automation import \
DEVICE_TRIGGER_BASE_SCHEMA
from homeassistant.components.device_automation import DEVICE_TRIGGER_BASE_SCHEMA
from homeassistant.components.homeassistant.triggers import state
from homeassistant.const import (CONF_DEVICE_ID, CONF_DOMAIN, CONF_ENTITY_ID,
CONF_PLATFORM, CONF_TYPE)
from homeassistant.const import (
CONF_DEVICE_ID,
CONF_DOMAIN,
CONF_ENTITY_ID,
CONF_PLATFORM,
CONF_TYPE,
)
from homeassistant.core import CALLBACK_TYPE, HomeAssistant
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers import device_registry
Expand Down
7 changes: 5 additions & 2 deletions custom_components/blue_current/entity.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Enitiy r."""
"""Entity representing a Blue Current charge point."""
from homeassistant.core import callback
from homeassistant.const import ATTR_NAME
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity import DeviceInfo, Entity

Expand All @@ -14,10 +15,12 @@ def __init__(self, connector: Connector, evse_id: str) -> None:
"""Initialize the entity."""
self.connector: Connector = connector

name = connector.charge_points[evse_id][ATTR_NAME]

self.evse_id = evse_id
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, evse_id)},
name=evse_id,
name=name if name != "" else evse_id,
manufacturer="Blue Current",
model=connector.charge_points[evse_id][MODEL_TYPE],
)
Expand Down
2 changes: 1 addition & 1 deletion custom_components/blue_current/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
"documentation": "https://www.home-assistant.io/integrations/blue_current",
"iot_class": "cloud_push",
"issue_tracker": "https://github.com/bluecurrent/ha-bluecurrent/issues",
"requirements": ["bluecurrent-api==1.0.3"],
"requirements": ["bluecurrent-api==1.0.4"],
"version": "1.0.0"
}
18 changes: 12 additions & 6 deletions custom_components/blue_current/sensor.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
"""Support for Blue Current sensors."""
from __future__ import annotations

from homeassistant.components.sensor import (SensorDeviceClass, SensorEntity,
SensorEntityDescription,
SensorStateClass)
from homeassistant.components.sensor import (
SensorDeviceClass,
SensorEntity,
SensorEntityDescription,
SensorStateClass,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (UnitOfElectricCurrent,
UnitOfElectricPotential, UnitOfEnergy,
UnitOfPower)
from homeassistant.const import (
UnitOfElectricCurrent,
UnitOfElectricPotential,
UnitOfEnergy,
UnitOfPower,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback
Expand Down
2 changes: 1 addition & 1 deletion custom_components/blue_current/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"user": {
"data": {
"api_token": "[%key:common::config_flow::data::api_token%]",
"add_card": "Do you want to use your own charge card?"
"add_card": "Do you want to use your own charge card? (without a charge card sessions will not be charged to your account)"
},
"description": "Enter your Blue Current api token",
"title": "Authentication"
Expand Down
21 changes: 12 additions & 9 deletions custom_components/blue_current/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@
from typing import Any

from bluecurrent_api import Client
from homeassistant.components.switch import (SwitchDeviceClass, SwitchEntity,
SwitchEntityDescription)
from homeassistant.components.switch import (
SwitchDeviceClass,
SwitchEntity,
SwitchEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
Expand Down Expand Up @@ -43,21 +46,21 @@ class BlueCurrentSwitchEntityDescription(
has_entity_name=True,
),
BlueCurrentSwitchEntityDescription(
key="public_charging",
key="linked_charge_cards_only",
device_class=SwitchDeviceClass.SWITCH,
name="Public charging",
name="Linked charge cards only",
icon="mdi:account-group",
function=lambda client, evse_id, value: client.set_public_charging(
function=lambda client, evse_id, value: client.set_linked_charge_cards_only(
evse_id, value
),
has_entity_name=True,
),
BlueCurrentSwitchEntityDescription(
key="operative",
key="block",
device_class=SwitchDeviceClass.SWITCH,
name="Operative",
icon="mdi:power",
function=lambda client, evse_id, value: client.set_operative(evse_id, value),
name="Block",
icon="mdi:lock",
function=lambda client, evse_id, value: client.block(evse_id, value),
has_entity_name=True,
),
)
Expand Down
2 changes: 1 addition & 1 deletion custom_components/blue_current/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
},
"user": {
"data": {
"add_card": "Do you want to use your own charge card?",
"add_card": "Do you want to use your own charge card? (without a charge card sessions will not be charged to your account)",
"api_token": "API Token"
},
"description": "Enter your Blue Current api token",
Expand Down
8 changes: 3 additions & 5 deletions tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,9 @@ def init(
self.charge_points = data
self.grid = grid

with patch(
"custom_components.blue_current.PLATFORMS", [platform]
), patch.object(Connector, "__init__", init), patch(
"custom_components.blue_current.Client", autospec=True
):
with patch("custom_components.blue_current.PLATFORMS", [platform]), patch.object(
Connector, "__init__", init
), patch("custom_components.blue_current.Client", autospec=True):
config_entry = MockConfigEntry(
domain=DOMAIN,
entry_id="uuid",
Expand Down
Loading

0 comments on commit 1b77674

Please sign in to comment.