Bump fyta_cli to 0.6.0 (#123816)
* Bump fyta_cli to 0.5.1 * Code adjustments to enable strit typing * Update homeassistant/components/fyta/__init__.py Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * Update diagnostics * Update config_flow + init (ruff) * Update sensor * Update coordinator * Update homeassistant/components/fyta/diagnostics.py Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * Update homeassistant/components/fyta/diagnostics.py Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * Update homeassistant/components/fyta/sensor.py Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * Set one ph sensor to null/none * Update sensor * Clean-up (ruff) --------- Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>pull/124072/head
parent
e07768412a
commit
8a110abc82
|
@ -197,6 +197,7 @@ homeassistant.components.fritzbox_callmonitor.*
|
|||
homeassistant.components.fronius.*
|
||||
homeassistant.components.frontend.*
|
||||
homeassistant.components.fully_kiosk.*
|
||||
homeassistant.components.fyta.*
|
||||
homeassistant.components.generic_hygrostat.*
|
||||
homeassistant.components.generic_thermostat.*
|
||||
homeassistant.components.geo_location.*
|
||||
|
|
|
@ -4,7 +4,6 @@ from __future__ import annotations
|
|||
|
||||
from datetime import datetime
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from fyta_cli.fyta_connector import FytaConnector
|
||||
|
||||
|
@ -73,11 +72,11 @@ async def async_migrate_entry(hass: HomeAssistant, config_entry: ConfigEntry) ->
|
|||
fyta = FytaConnector(
|
||||
config_entry.data[CONF_USERNAME], config_entry.data[CONF_PASSWORD]
|
||||
)
|
||||
credentials: dict[str, Any] = await fyta.login()
|
||||
credentials = await fyta.login()
|
||||
await fyta.client.close()
|
||||
|
||||
new[CONF_ACCESS_TOKEN] = credentials[CONF_ACCESS_TOKEN]
|
||||
new[CONF_EXPIRATION] = credentials[CONF_EXPIRATION].isoformat()
|
||||
new[CONF_ACCESS_TOKEN] = credentials.access_token
|
||||
new[CONF_EXPIRATION] = credentials.expiration.isoformat()
|
||||
|
||||
hass.config_entries.async_update_entry(
|
||||
config_entry, data=new, minor_version=2, version=1
|
||||
|
|
|
@ -12,10 +12,11 @@ from fyta_cli.fyta_exceptions import (
|
|||
FytaConnectionError,
|
||||
FytaPasswordError,
|
||||
)
|
||||
from fyta_cli.fyta_models import Credentials
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
|
||||
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
|
||||
from homeassistant.const import CONF_ACCESS_TOKEN, CONF_PASSWORD, CONF_USERNAME
|
||||
from homeassistant.helpers.selector import (
|
||||
TextSelector,
|
||||
TextSelectorConfig,
|
||||
|
@ -49,14 +50,11 @@ DATA_SCHEMA = vol.Schema(
|
|||
class FytaConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a config flow for Fyta."""
|
||||
|
||||
credentials: Credentials
|
||||
_entry: FytaConfigEntry | None = None
|
||||
VERSION = 1
|
||||
MINOR_VERSION = 2
|
||||
|
||||
def __init__(self) -> None:
|
||||
"""Initialize FytaConfigFlow."""
|
||||
self.credentials: dict[str, Any] = {}
|
||||
self._entry: FytaConfigEntry | None = None
|
||||
|
||||
async def async_auth(self, user_input: Mapping[str, Any]) -> dict[str, str]:
|
||||
"""Reusable Auth Helper."""
|
||||
fyta = FytaConnector(user_input[CONF_USERNAME], user_input[CONF_PASSWORD])
|
||||
|
@ -75,10 +73,6 @@ class FytaConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||
finally:
|
||||
await fyta.client.close()
|
||||
|
||||
self.credentials[CONF_EXPIRATION] = self.credentials[
|
||||
CONF_EXPIRATION
|
||||
].isoformat()
|
||||
|
||||
return {}
|
||||
|
||||
async def async_step_user(
|
||||
|
@ -90,7 +84,10 @@ class FytaConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||
self._async_abort_entries_match({CONF_USERNAME: user_input[CONF_USERNAME]})
|
||||
|
||||
if not (errors := await self.async_auth(user_input)):
|
||||
user_input |= self.credentials
|
||||
user_input |= {
|
||||
CONF_ACCESS_TOKEN: self.credentials.access_token,
|
||||
CONF_EXPIRATION: self.credentials.expiration.isoformat(),
|
||||
}
|
||||
return self.async_create_entry(
|
||||
title=user_input[CONF_USERNAME], data=user_input
|
||||
)
|
||||
|
@ -114,7 +111,10 @@ class FytaConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||
assert self._entry is not None
|
||||
|
||||
if user_input and not (errors := await self.async_auth(user_input)):
|
||||
user_input |= self.credentials
|
||||
user_input |= {
|
||||
CONF_ACCESS_TOKEN: self.credentials.access_token,
|
||||
CONF_EXPIRATION: self.credentials.expiration.isoformat(),
|
||||
}
|
||||
return self.async_update_reload_and_abort(
|
||||
self._entry, data={**self._entry.data, **user_input}
|
||||
)
|
||||
|
|
|
@ -4,7 +4,7 @@ from __future__ import annotations
|
|||
|
||||
from datetime import datetime, timedelta
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, Any
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from fyta_cli.fyta_connector import FytaConnector
|
||||
from fyta_cli.fyta_exceptions import (
|
||||
|
@ -13,6 +13,7 @@ from fyta_cli.fyta_exceptions import (
|
|||
FytaPasswordError,
|
||||
FytaPlantError,
|
||||
)
|
||||
from fyta_cli.fyta_models import Plant
|
||||
|
||||
from homeassistant.const import CONF_ACCESS_TOKEN
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
@ -27,7 +28,7 @@ if TYPE_CHECKING:
|
|||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class FytaCoordinator(DataUpdateCoordinator[dict[int, dict[str, Any]]]):
|
||||
class FytaCoordinator(DataUpdateCoordinator[dict[int, Plant]]):
|
||||
"""Fyta custom coordinator."""
|
||||
|
||||
config_entry: FytaConfigEntry
|
||||
|
@ -44,7 +45,7 @@ class FytaCoordinator(DataUpdateCoordinator[dict[int, dict[str, Any]]]):
|
|||
|
||||
async def _async_update_data(
|
||||
self,
|
||||
) -> dict[int, dict[str, Any]]:
|
||||
) -> dict[int, Plant]:
|
||||
"""Fetch data from API endpoint."""
|
||||
|
||||
if (
|
||||
|
@ -60,7 +61,6 @@ class FytaCoordinator(DataUpdateCoordinator[dict[int, dict[str, Any]]]):
|
|||
|
||||
async def renew_authentication(self) -> bool:
|
||||
"""Renew access token for FYTA API."""
|
||||
credentials: dict[str, Any] = {}
|
||||
|
||||
try:
|
||||
credentials = await self.fyta.login()
|
||||
|
@ -70,8 +70,8 @@ class FytaCoordinator(DataUpdateCoordinator[dict[int, dict[str, Any]]]):
|
|||
raise ConfigEntryAuthFailed from ex
|
||||
|
||||
new_config_entry = {**self.config_entry.data}
|
||||
new_config_entry[CONF_ACCESS_TOKEN] = credentials[CONF_ACCESS_TOKEN]
|
||||
new_config_entry[CONF_EXPIRATION] = credentials[CONF_EXPIRATION].isoformat()
|
||||
new_config_entry[CONF_ACCESS_TOKEN] = credentials.access_token
|
||||
new_config_entry[CONF_EXPIRATION] = credentials.expiration.isoformat()
|
||||
|
||||
self.hass.config_entries.async_update_entry(
|
||||
self.config_entry, data=new_config_entry
|
||||
|
|
|
@ -25,5 +25,5 @@ async def async_get_config_entry_diagnostics(
|
|||
|
||||
return {
|
||||
"config_entry": async_redact_data(config_entry.as_dict(), TO_REDACT),
|
||||
"plant_data": data,
|
||||
"plant_data": {key: value.to_dict() for key, value in data.items()},
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""Entities for FYTA integration."""
|
||||
|
||||
from typing import Any
|
||||
from fyta_cli.fyta_models import Plant
|
||||
|
||||
from homeassistant.components.sensor import SensorEntityDescription
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
|
@ -32,13 +32,13 @@ class FytaPlantEntity(CoordinatorEntity[FytaCoordinator]):
|
|||
manufacturer="Fyta",
|
||||
model="Plant",
|
||||
identifiers={(DOMAIN, f"{entry.entry_id}-{plant_id}")},
|
||||
name=self.plant.get("name"),
|
||||
sw_version=self.plant.get("sw_version"),
|
||||
name=self.plant.name,
|
||||
sw_version=self.plant.sw_version,
|
||||
)
|
||||
self.entity_description = description
|
||||
|
||||
@property
|
||||
def plant(self) -> dict[str, Any]:
|
||||
def plant(self) -> Plant:
|
||||
"""Get plant data."""
|
||||
return self.coordinator.data[self.plant_id]
|
||||
|
||||
|
|
|
@ -7,5 +7,5 @@
|
|||
"integration_type": "hub",
|
||||
"iot_class": "cloud_polling",
|
||||
"quality_scale": "platinum",
|
||||
"requirements": ["fyta_cli==0.4.1"]
|
||||
"requirements": ["fyta_cli==0.6.0"]
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ from dataclasses import dataclass
|
|||
from datetime import datetime
|
||||
from typing import Final
|
||||
|
||||
from fyta_cli.fyta_connector import PLANT_MEASUREMENT_STATUS, PLANT_STATUS
|
||||
from fyta_cli.fyta_models import Plant
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
SensorDeviceClass,
|
||||
|
@ -23,19 +23,18 @@ from homeassistant.const import (
|
|||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import StateType
|
||||
|
||||
from . import FytaConfigEntry
|
||||
from .coordinator import FytaCoordinator
|
||||
from .entity import FytaPlantEntity
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class FytaSensorEntityDescription(SensorEntityDescription):
|
||||
"""Describes Fyta sensor entity."""
|
||||
|
||||
value_fn: Callable[[str | int | float | datetime], str | int | float | datetime] = (
|
||||
lambda value: value
|
||||
)
|
||||
value_fn: Callable[[Plant], StateType | datetime]
|
||||
|
||||
|
||||
PLANT_STATUS_LIST: list[str] = ["deleted", "doing_great", "need_attention", "no_sensor"]
|
||||
|
@ -48,63 +47,68 @@ PLANT_MEASUREMENT_STATUS_LIST: list[str] = [
|
|||
"too_high",
|
||||
]
|
||||
|
||||
|
||||
SENSORS: Final[list[FytaSensorEntityDescription]] = [
|
||||
FytaSensorEntityDescription(
|
||||
key="scientific_name",
|
||||
translation_key="scientific_name",
|
||||
value_fn=lambda plant: plant.scientific_name,
|
||||
),
|
||||
FytaSensorEntityDescription(
|
||||
key="status",
|
||||
translation_key="plant_status",
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
options=PLANT_STATUS_LIST,
|
||||
value_fn=PLANT_STATUS.get,
|
||||
value_fn=lambda plant: plant.status.name.lower(),
|
||||
),
|
||||
FytaSensorEntityDescription(
|
||||
key="temperature_status",
|
||||
translation_key="temperature_status",
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
options=PLANT_MEASUREMENT_STATUS_LIST,
|
||||
value_fn=PLANT_MEASUREMENT_STATUS.get,
|
||||
value_fn=lambda plant: plant.temperature_status.name.lower(),
|
||||
),
|
||||
FytaSensorEntityDescription(
|
||||
key="light_status",
|
||||
translation_key="light_status",
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
options=PLANT_MEASUREMENT_STATUS_LIST,
|
||||
value_fn=PLANT_MEASUREMENT_STATUS.get,
|
||||
value_fn=lambda plant: plant.light_status.name.lower(),
|
||||
),
|
||||
FytaSensorEntityDescription(
|
||||
key="moisture_status",
|
||||
translation_key="moisture_status",
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
options=PLANT_MEASUREMENT_STATUS_LIST,
|
||||
value_fn=PLANT_MEASUREMENT_STATUS.get,
|
||||
value_fn=lambda plant: plant.moisture_status.name.lower(),
|
||||
),
|
||||
FytaSensorEntityDescription(
|
||||
key="salinity_status",
|
||||
translation_key="salinity_status",
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
options=PLANT_MEASUREMENT_STATUS_LIST,
|
||||
value_fn=PLANT_MEASUREMENT_STATUS.get,
|
||||
value_fn=lambda plant: plant.salinity_status.name.lower(),
|
||||
),
|
||||
FytaSensorEntityDescription(
|
||||
key="temperature",
|
||||
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||
device_class=SensorDeviceClass.TEMPERATURE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda plant: plant.temperature,
|
||||
),
|
||||
FytaSensorEntityDescription(
|
||||
key="light",
|
||||
translation_key="light",
|
||||
native_unit_of_measurement="μmol/s⋅m²",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda plant: plant.light,
|
||||
),
|
||||
FytaSensorEntityDescription(
|
||||
key="moisture",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
device_class=SensorDeviceClass.MOISTURE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda plant: plant.moisture,
|
||||
),
|
||||
FytaSensorEntityDescription(
|
||||
key="salinity",
|
||||
|
@ -112,11 +116,13 @@ SENSORS: Final[list[FytaSensorEntityDescription]] = [
|
|||
native_unit_of_measurement=UnitOfConductivity.MILLISIEMENS,
|
||||
device_class=SensorDeviceClass.CONDUCTIVITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda plant: plant.salinity,
|
||||
),
|
||||
FytaSensorEntityDescription(
|
||||
key="ph",
|
||||
device_class=SensorDeviceClass.PH,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda plant: plant.ph,
|
||||
),
|
||||
FytaSensorEntityDescription(
|
||||
key="battery_level",
|
||||
|
@ -124,6 +130,7 @@ SENSORS: Final[list[FytaSensorEntityDescription]] = [
|
|||
device_class=SensorDeviceClass.BATTERY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
value_fn=lambda plant: plant.battery_level,
|
||||
),
|
||||
]
|
||||
|
||||
|
@ -138,7 +145,7 @@ async def async_setup_entry(
|
|||
FytaPlantSensor(coordinator, entry, sensor, plant_id)
|
||||
for plant_id in coordinator.fyta.plant_list
|
||||
for sensor in SENSORS
|
||||
if sensor.key in coordinator.data[plant_id]
|
||||
if sensor.key in dir(coordinator.data[plant_id])
|
||||
]
|
||||
|
||||
async_add_entities(plant_entities)
|
||||
|
@ -150,8 +157,7 @@ class FytaPlantSensor(FytaPlantEntity, SensorEntity):
|
|||
entity_description: FytaSensorEntityDescription
|
||||
|
||||
@property
|
||||
def native_value(self) -> str | int | float | datetime:
|
||||
def native_value(self) -> StateType | datetime:
|
||||
"""Return the state for this sensor."""
|
||||
|
||||
val = self.plant[self.entity_description.key]
|
||||
return self.entity_description.value_fn(val)
|
||||
return self.entity_description.value_fn(self.plant)
|
||||
|
|
10
mypy.ini
10
mypy.ini
|
@ -1726,6 +1726,16 @@ disallow_untyped_defs = true
|
|||
warn_return_any = true
|
||||
warn_unreachable = true
|
||||
|
||||
[mypy-homeassistant.components.fyta.*]
|
||||
check_untyped_defs = true
|
||||
disallow_incomplete_defs = true
|
||||
disallow_subclassing_any = true
|
||||
disallow_untyped_calls = true
|
||||
disallow_untyped_decorators = true
|
||||
disallow_untyped_defs = true
|
||||
warn_return_any = true
|
||||
warn_unreachable = true
|
||||
|
||||
[mypy-homeassistant.components.generic_hygrostat.*]
|
||||
check_untyped_defs = true
|
||||
disallow_incomplete_defs = true
|
||||
|
|
|
@ -921,7 +921,7 @@ freesms==0.2.0
|
|||
fritzconnection[qr]==1.13.2
|
||||
|
||||
# homeassistant.components.fyta
|
||||
fyta_cli==0.4.1
|
||||
fyta_cli==0.6.0
|
||||
|
||||
# homeassistant.components.google_translate
|
||||
gTTS==2.2.4
|
||||
|
|
|
@ -774,7 +774,7 @@ freebox-api==1.1.0
|
|||
fritzconnection[qr]==1.13.2
|
||||
|
||||
# homeassistant.components.fyta
|
||||
fyta_cli==0.4.1
|
||||
fyta_cli==0.6.0
|
||||
|
||||
# homeassistant.components.google_translate
|
||||
gTTS==2.2.4
|
||||
|
|
|
@ -4,6 +4,7 @@ from collections.abc import Generator
|
|||
from datetime import UTC, datetime
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from fyta_cli.fyta_models import Credentials, Plant
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.fyta.const import CONF_EXPIRATION, DOMAIN as FYTA_DOMAIN
|
||||
|
@ -35,23 +36,27 @@ def mock_config_entry() -> MockConfigEntry:
|
|||
def mock_fyta_connector():
|
||||
"""Build a fixture for the Fyta API that connects successfully and returns one device."""
|
||||
|
||||
plants: dict[int, Plant] = {
|
||||
0: Plant.from_dict(load_json_object_fixture("plant_status1.json", FYTA_DOMAIN)),
|
||||
1: Plant.from_dict(load_json_object_fixture("plant_status2.json", FYTA_DOMAIN)),
|
||||
}
|
||||
|
||||
mock_fyta_connector = AsyncMock()
|
||||
mock_fyta_connector.expiration = datetime.fromisoformat(EXPIRATION).replace(
|
||||
tzinfo=UTC
|
||||
)
|
||||
mock_fyta_connector.client = AsyncMock(autospec=True)
|
||||
mock_fyta_connector.update_all_plants.return_value = load_json_object_fixture(
|
||||
"plant_status.json", FYTA_DOMAIN
|
||||
)
|
||||
mock_fyta_connector.plant_list = load_json_object_fixture(
|
||||
"plant_list.json", FYTA_DOMAIN
|
||||
)
|
||||
mock_fyta_connector.update_all_plants.return_value = plants
|
||||
mock_fyta_connector.plant_list = {
|
||||
0: "Gummibaum",
|
||||
1: "Kakaobaum",
|
||||
}
|
||||
|
||||
mock_fyta_connector.login = AsyncMock(
|
||||
return_value={
|
||||
CONF_ACCESS_TOKEN: ACCESS_TOKEN,
|
||||
CONF_EXPIRATION: datetime.fromisoformat(EXPIRATION).replace(tzinfo=UTC),
|
||||
}
|
||||
return_value=Credentials(
|
||||
access_token=ACCESS_TOKEN,
|
||||
expiration=datetime.fromisoformat(EXPIRATION).replace(tzinfo=UTC),
|
||||
)
|
||||
)
|
||||
with (
|
||||
patch(
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"0": "Gummibaum",
|
||||
"1": "Kakaobaum"
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
{
|
||||
"0": {
|
||||
"name": "Gummibaum",
|
||||
"scientific_name": "Ficus elastica",
|
||||
"status": 1,
|
||||
"sw_version": "1.0"
|
||||
},
|
||||
"1": {
|
||||
"name": "Kakaobaum",
|
||||
"scientific_name": "Theobroma cacao",
|
||||
"status": 2,
|
||||
"sw_version": "1.0"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"battery_level": 80,
|
||||
"battery_status": true,
|
||||
"last_updated": "2023-01-10 10:10:00",
|
||||
"light": 2,
|
||||
"light_status": 3,
|
||||
"nickname": "Gummibaum",
|
||||
"moisture": 61,
|
||||
"moisture_status": 3,
|
||||
"sensor_available": true,
|
||||
"sw_version": "1.0",
|
||||
"status": 3,
|
||||
"online": true,
|
||||
"ph": null,
|
||||
"plant_id": 0,
|
||||
"plant_origin_path": "",
|
||||
"plant_thumb_path": "",
|
||||
"salinity": 1,
|
||||
"salinity_status": 4,
|
||||
"scientific_name": "Ficus elastica",
|
||||
"temperature": 25.2,
|
||||
"temperature_status": 3
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"battery_level": 80,
|
||||
"battery_status": true,
|
||||
"last_updated": "2023-01-02 10:10:00",
|
||||
"light": 2,
|
||||
"light_status": 3,
|
||||
"nickname": "Kakaobaum",
|
||||
"moisture": 61,
|
||||
"moisture_status": 3,
|
||||
"sensor_available": true,
|
||||
"sw_version": "1.0",
|
||||
"status": 3,
|
||||
"online": true,
|
||||
"ph": 7,
|
||||
"plant_id": 0,
|
||||
"plant_origin_path": "",
|
||||
"plant_thumb_path": "",
|
||||
"salinity": 1,
|
||||
"salinity_status": 4,
|
||||
"scientific_name": "Theobroma cacao",
|
||||
"temperature": 25.2,
|
||||
"temperature_status": 3
|
||||
}
|
|
@ -23,16 +23,50 @@
|
|||
}),
|
||||
'plant_data': dict({
|
||||
'0': dict({
|
||||
'battery_level': 80.0,
|
||||
'battery_status': True,
|
||||
'last_updated': '2023-01-10T10:10:00',
|
||||
'light': 2.0,
|
||||
'light_status': 3,
|
||||
'moisture': 61.0,
|
||||
'moisture_status': 3,
|
||||
'name': 'Gummibaum',
|
||||
'online': True,
|
||||
'ph': None,
|
||||
'plant_id': 0,
|
||||
'plant_origin_path': '',
|
||||
'plant_thumb_path': '',
|
||||
'salinity': 1.0,
|
||||
'salinity_status': 4,
|
||||
'scientific_name': 'Ficus elastica',
|
||||
'status': 1,
|
||||
'sensor_available': True,
|
||||
'status': 3,
|
||||
'sw_version': '1.0',
|
||||
'temperature': 25.2,
|
||||
'temperature_status': 3,
|
||||
}),
|
||||
'1': dict({
|
||||
'battery_level': 80.0,
|
||||
'battery_status': True,
|
||||
'last_updated': '2023-01-02T10:10:00',
|
||||
'light': 2.0,
|
||||
'light_status': 3,
|
||||
'moisture': 61.0,
|
||||
'moisture_status': 3,
|
||||
'name': 'Kakaobaum',
|
||||
'online': True,
|
||||
'ph': 7.0,
|
||||
'plant_id': 0,
|
||||
'plant_origin_path': '',
|
||||
'plant_thumb_path': '',
|
||||
'salinity': 1.0,
|
||||
'salinity_status': 4,
|
||||
'scientific_name': 'Theobroma cacao',
|
||||
'status': 2,
|
||||
'sensor_available': True,
|
||||
'status': 3,
|
||||
'sw_version': '1.0',
|
||||
'temperature': 25.2,
|
||||
'temperature_status': 3,
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue