Skip to content
This repository has been archived by the owner on Jan 5, 2024. It is now read-only.

Commit

Permalink
Merge pull request #7 from rccoleman/dev
Browse files Browse the repository at this point in the history
Merge dev to main
  • Loading branch information
rccoleman authored Dec 9, 2020
2 parents cb84cdb + 100806d commit 0232bdb
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 69 deletions.
20 changes: 8 additions & 12 deletions custom_components/lamarzocco/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,8 @@
CONF_SERIAL_NUMBER,
CONF_CLIENT_ID,
CONF_CLIENT_SECRET,
MACHINE_STATUS,
STATUS_ON,
GW_URL,
TOKEN_URL,
)

PLATFORMS = ["switch"]
Expand Down Expand Up @@ -121,28 +120,27 @@ def __init__(self, hass, config):
self.hass = hass
self._config = config
self.current_data = {}
self.current_status = {}
self.client = None
self.is_on = False

async def init_data(self):
"""Machine data inialization"""
serial_number = self._config[CONF_SERIAL_NUMBER]
self.config_endpoint = f"{GW_URL}/{serial_number}/configuration"
self.status_endpoint = f"{GW_URL}/{serial_number}/status"
token_endpoint = "https://cms.lamarzocco.io/oauth/v2/token"
client_id = self._config[CONF_CLIENT_ID]
client_secret = self._config[CONF_CLIENT_SECRET]

self.client = AsyncOAuth2Client(
client_id=client_id,
client_secret=client_secret,
token_endpoint=token_endpoint,
token_endpoint=TOKEN_URL,
)

headers = {"client_id": client_id, "client_secret": client_secret}

await self.client.fetch_token(
url=token_endpoint,
url=TOKEN_URL,
username=self._config[CONF_USERNAME],
password=self._config[CONF_PASSWORD],
headers=headers,
Expand All @@ -154,17 +152,15 @@ async def fetch_data(self):

current_status = await self.client.get(self.status_endpoint)
if current_status is not None:
_LOGGER.debug(current_status.json())
data = current_status.json()
if data is not None:
self.is_on = data[DATA_TAG][MACHINE_STATUS] == STATUS_ON
_LOGGER.debug(current_status.content)
self.current_status = current_status.json().get(DATA_TAG)

current_data = await self.client.get(self.config_endpoint)
if current_data is not None:
_LOGGER.debug(current_data.json())
_LOGGER.debug(current_data.content)
self.current_data = current_data.json().get(DATA_TAG)

_LOGGER.debug("Device is {}".format("On" if self.is_on else "Off"))
_LOGGER.debug("Status is {}".format(self.current_status))
_LOGGER.debug("Data is {}".format(self.current_data))
return self

Expand Down
105 changes: 63 additions & 42 deletions custom_components/lamarzocco/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,55 +8,76 @@

DEFAULT_NAME = "Espresso Machine"

ATTR_ENABLE_PREBREWING = "ENABLE_PREBREWING"
ATTR_STBY_TIMER = "STBY_TIMER"
ATTR_TON_PREBREWING_K1 = "TON_PREBREWING_K1"
ATTR_TON_PREBREWING_K2 = "TON_PREBREWING_K2"
ATTR_TON_PREBREWING_K3 = "TON_PREBREWING_K3"
ATTR_TON_PREBREWING_K4 = "TON_PREBREWING_K4"
ATTR_TOFF_PREBREWING_K1 = "TOFF_PREBREWING_K1"
ATTR_TOFF_PREBREWING_K2 = "TOFF_PREBREWING_K2"
ATTR_TOFF_PREBREWING_K3 = "TOFF_PREBREWING_K3"
ATTR_TOFF_PREBREWING_K4 = "TOFF_PREBREWING_K4"
ATTR_TSET_STEAM = "TSET_STEAM"
ATTR_TSET_COFFEE = "TSET_COFFEE"
ATTR_DOSE_K1 = "DOSE_K1"
ATTR_DOSE_K2 = "DOSE_K2"
ATTR_DOSE_K3 = "DOSE_K3"
ATTR_DOSE_K4 = "DOSE_K4"
ATTR_DOSE_K5 = "DOSE_K5"
ATTR_DOSE_TEA = "DOSE_TEA"
STATE_STATUS = "status"
ATTRIBUTION = "Data from La Marzocco"

DATA_TAG = "data"

DATA_ENABLE_PREBREWING = "ENABLE_PREBREWING"
DATA_STBY_TIMER = "STBY_TIMER"
DATA_TON_PREBREWING_K1 = "TON_PREBREWING_K1"
DATA_TON_PREBREWING_K2 = "TON_PREBREWING_K2"
DATA_TON_PREBREWING_K3 = "TON_PREBREWING_K3"
DATA_TON_PREBREWING_K4 = "TON_PREBREWING_K4"
DATA_TOFF_PREBREWING_K1 = "TOFF_PREBREWING_K1"
DATA_TOFF_PREBREWING_K2 = "TOFF_PREBREWING_K2"
DATA_TOFF_PREBREWING_K3 = "TOFF_PREBREWING_K3"
DATA_TOFF_PREBREWING_K4 = "TOFF_PREBREWING_K4"
DATA_TSET_STEAM = "TSET_STEAM"
DATA_TSET_COFFEE = "TSET_COFFEE"
DATA_DOSE_K1 = "DOSE_K1"
DATA_DOSE_K2 = "DOSE_K2"
DATA_DOSE_K3 = "DOSE_K3"
DATA_DOSE_K4 = "DOSE_K4"
DATA_DOSE_K5 = "DOSE_K5"
DATA_DOSE_TEA = "DOSE_TEA"

STATUS_ON = "ON"
STATUS_STANDBY = "STANDBY"
MACHINE_STATUS = "MACHINE_STATUS"

STATUS_MAP = {STATUS_ON: "On", STATUS_STANDBY: "Standby"}
STATUS_MACHINE_STATUS = "MACHINE_STATUS"
STATUS_TEMP_STEAM = "TEMP_STEAM"
STATUS_TEMP_COFFEE = "TEMP_COFFEE"

RECEIVED_DATETIME = "received"

COMMAND_ON = {"status": "ON"}
COMMAND_STANDBY = {"status": "STANDBY"}

TEMP_KEYS = ["TSET", "TEMP"]

GW_URL = "https://gw.lamarzocco.io/v1/home/machines"
TOKEN_URL = "https://cms.lamarzocco.io/oauth/v2/token"
CUSTOMER_URL = "https://cms.lamarzocco.io/api/customer"

DEVICE_MAP = {
"GS": "GS/3",
"LM": "Linea Mini",
}

ATTR_DATA_MAP = {
RECEIVED_DATETIME: "data_last_changed",
DATA_ENABLE_PREBREWING: "prebrewing_enabled",
DATA_STBY_TIMER: "standby_timer",
DATA_TON_PREBREWING_K1: "prebrewing_ton_k1",
DATA_TON_PREBREWING_K2: "prebrewing_ton_k2",
DATA_TON_PREBREWING_K3: "prebrewing_ton_k3",
DATA_TON_PREBREWING_K4: "prebrewing_ton_k4",
DATA_TOFF_PREBREWING_K1: "prebrewing_toff_k1",
DATA_TOFF_PREBREWING_K2: "prebrewing_toff_k2",
DATA_TOFF_PREBREWING_K3: "prebrewing_toff_k3",
DATA_TOFF_PREBREWING_K4: "prebrewing_toff_k4",
DATA_TSET_STEAM: "steam_temperature",
DATA_TSET_COFFEE: "coffee_temperature",
DATA_DOSE_K1: "dose_k1",
DATA_DOSE_K2: "dose_k2",
DATA_DOSE_K3: "dose_k3",
DATA_DOSE_K4: "dose_k4",
DATA_DOSE_K5: "dose_k5",
DATA_DOSE_TEA: "dose_tea",
}

ATTR_MAP = {
STATE_STATUS: "status",
ATTR_ENABLE_PREBREWING: "prebrewing_enabled",
ATTR_STBY_TIMER: "standby_timer",
ATTR_TON_PREBREWING_K1: "prebrewing_ton_k1",
ATTR_TON_PREBREWING_K2: "prebrewing_ton_k2",
ATTR_TON_PREBREWING_K3: "prebrewing_ton_k3",
ATTR_TON_PREBREWING_K4: "prebrewing_ton_k4",
ATTR_TOFF_PREBREWING_K1: "prebrewing_toff_k1",
ATTR_TOFF_PREBREWING_K2: "prebrewing_toff_k2",
ATTR_TOFF_PREBREWING_K3: "prebrewing_toff_k3",
ATTR_TOFF_PREBREWING_K4: "prebrewing_toff_k4",
ATTR_TSET_STEAM: "steam_temperature",
ATTR_TSET_COFFEE: "coffee_temperature",
ATTR_DOSE_K1: "dose_k1",
ATTR_DOSE_K2: "dose_k2",
ATTR_DOSE_K3: "dose_k3",
ATTR_DOSE_K4: "dose_k4",
ATTR_DOSE_K5: "dose_k5",
ATTR_DOSE_TEA: "dose_tea",
}
ATTR_STATUS_MAP = {
RECEIVED_DATETIME: "status_last_changed",
STATUS_TEMP_STEAM: "steam_temp",
STATUS_TEMP_COFFEE: "coffee_temp",
}
55 changes: 40 additions & 15 deletions custom_components/lamarzocco/switch.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
from typing import Dict
from homeassistant.components.switch import SwitchEntity
from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.core import DOMAIN, callback
import logging
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from homeassistant.util.dt import as_local, parse_datetime
from .const import (
ATTR_DATA_MAP,
ATTR_STATUS_MAP,
DEVICE_MAP,
DOMAIN,
CONF_SERIAL_NUMBER,
DEFAULT_NAME,
ATTR_MAP,
RECEIVED_DATETIME,
STATUS_MACHINE_STATUS,
STATUS_ON,
TEMP_KEYS,
ATTRIBUTION,
)

_LOGGER = logging.getLogger(__name__)

ATTRIBUTION = "Data from La Marzocco"


async def async_setup_entry(hass, config_entry, async_add_entities):
"""Add a switch entity from a config_entry."""
Expand All @@ -31,6 +38,9 @@ def __init__(self, coordinator, config, is_metric):
super().__init__(coordinator)
self._config = config
self._temp_state = None
self._is_on = (
coordinator.data.current_status[STATUS_MACHINE_STATUS] == STATUS_ON
)
self.is_metric = is_metric

async def async_turn_on(self, **kwargs) -> None:
Expand All @@ -54,7 +64,9 @@ def _handle_coordinator_update(self) -> None:
@callback
def update_from_latest_data(self) -> None:
"""Update the state."""
if self._temp_state == self.coordinator.data.is_on:
status = self.coordinator.data.current_status[STATUS_MACHINE_STATUS]
self._is_on = status == STATUS_ON
if self._temp_state == self._is_on:
self._temp_state = None

@property
Expand All @@ -65,11 +77,7 @@ def unique_id(self):
@property
def is_on(self) -> bool:
"""Return true if device is on."""
return (
self._temp_state
if self._temp_state is not None
else self.coordinator.data.is_on
)
return self._temp_state if self._temp_state is not None else self._is_on

@property
def assumed_state(self) -> bool:
Expand All @@ -94,22 +102,37 @@ def attribution(self):
@property
def state_attributes(self):
"""Return the state attributes."""
output = self.generate_attrs(
self.coordinator.data.current_status, ATTR_STATUS_MAP
)

output.update(
self.generate_attrs(self.coordinator.data.current_data, ATTR_DATA_MAP)
)

return output

def generate_attrs(self, data, map) -> Dict:
output = {}

current_data = self.coordinator.data.current_data
for key in current_data:
if key in ATTR_MAP.keys():
value = current_data[key]
for key in data:
if key in map.keys():
value = data[key]

"""Convert boolean values to strings to improve display in Lovelace"""
if isinstance(value, bool):
value = str(value)

"""Convert temps to fahrenheit if needed"""
if not self.is_metric and "TSET" in key:
if not self.is_metric and any(val in key for val in TEMP_KEYS):
value = round((value * 9 / 5) + 32, 1)

output[ATTR_MAP[key]] = value
"""Convert dates to datetime"""
if RECEIVED_DATETIME in key:
value = parse_datetime(value)

output[map[key]] = value

return output

Expand All @@ -121,11 +144,13 @@ def icon(self) -> str:
@property
def device_info(self):
"""Device info."""
prefix = self._config[CONF_SERIAL_NUMBER][:2]

return {
"identifiers": {(DOMAIN,)},
"name": "La Marzocco",
"manufacturer": "La Marzocco",
"model": "GS/3",
"model": DEVICE_MAP[prefix] if prefix in DEVICE_MAP.keys() else "No Model",
"default_name": "lamarzocco",
"entry_type": "None",
}

0 comments on commit 0232bdb

Please sign in to comment.