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>
This commit is contained in:
dontinelli 2024-08-16 17:46:37 +02:00 committed by GitHub
parent e07768412a
commit 8a110abc82
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 1279 additions and 76 deletions

View File

@ -197,6 +197,7 @@ homeassistant.components.fritzbox_callmonitor.*
homeassistant.components.fronius.* homeassistant.components.fronius.*
homeassistant.components.frontend.* homeassistant.components.frontend.*
homeassistant.components.fully_kiosk.* homeassistant.components.fully_kiosk.*
homeassistant.components.fyta.*
homeassistant.components.generic_hygrostat.* homeassistant.components.generic_hygrostat.*
homeassistant.components.generic_thermostat.* homeassistant.components.generic_thermostat.*
homeassistant.components.geo_location.* homeassistant.components.geo_location.*

View File

@ -4,7 +4,6 @@ from __future__ import annotations
from datetime import datetime from datetime import datetime
import logging import logging
from typing import Any
from fyta_cli.fyta_connector import FytaConnector from fyta_cli.fyta_connector import FytaConnector
@ -73,11 +72,11 @@ async def async_migrate_entry(hass: HomeAssistant, config_entry: ConfigEntry) ->
fyta = FytaConnector( fyta = FytaConnector(
config_entry.data[CONF_USERNAME], config_entry.data[CONF_PASSWORD] 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() await fyta.client.close()
new[CONF_ACCESS_TOKEN] = credentials[CONF_ACCESS_TOKEN] new[CONF_ACCESS_TOKEN] = credentials.access_token
new[CONF_EXPIRATION] = credentials[CONF_EXPIRATION].isoformat() new[CONF_EXPIRATION] = credentials.expiration.isoformat()
hass.config_entries.async_update_entry( hass.config_entries.async_update_entry(
config_entry, data=new, minor_version=2, version=1 config_entry, data=new, minor_version=2, version=1

View File

@ -12,10 +12,11 @@ from fyta_cli.fyta_exceptions import (
FytaConnectionError, FytaConnectionError,
FytaPasswordError, FytaPasswordError,
) )
from fyta_cli.fyta_models import Credentials
import voluptuous as vol import voluptuous as vol
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult 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 ( from homeassistant.helpers.selector import (
TextSelector, TextSelector,
TextSelectorConfig, TextSelectorConfig,
@ -49,14 +50,11 @@ DATA_SCHEMA = vol.Schema(
class FytaConfigFlow(ConfigFlow, domain=DOMAIN): class FytaConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for Fyta.""" """Handle a config flow for Fyta."""
credentials: Credentials
_entry: FytaConfigEntry | None = None
VERSION = 1 VERSION = 1
MINOR_VERSION = 2 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]: async def async_auth(self, user_input: Mapping[str, Any]) -> dict[str, str]:
"""Reusable Auth Helper.""" """Reusable Auth Helper."""
fyta = FytaConnector(user_input[CONF_USERNAME], user_input[CONF_PASSWORD]) fyta = FytaConnector(user_input[CONF_USERNAME], user_input[CONF_PASSWORD])
@ -75,10 +73,6 @@ class FytaConfigFlow(ConfigFlow, domain=DOMAIN):
finally: finally:
await fyta.client.close() await fyta.client.close()
self.credentials[CONF_EXPIRATION] = self.credentials[
CONF_EXPIRATION
].isoformat()
return {} return {}
async def async_step_user( 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]}) self._async_abort_entries_match({CONF_USERNAME: user_input[CONF_USERNAME]})
if not (errors := await self.async_auth(user_input)): 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( return self.async_create_entry(
title=user_input[CONF_USERNAME], data=user_input title=user_input[CONF_USERNAME], data=user_input
) )
@ -114,7 +111,10 @@ class FytaConfigFlow(ConfigFlow, domain=DOMAIN):
assert self._entry is not None assert self._entry is not None
if user_input and not (errors := await self.async_auth(user_input)): 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( return self.async_update_reload_and_abort(
self._entry, data={**self._entry.data, **user_input} self._entry, data={**self._entry.data, **user_input}
) )

View File

@ -4,7 +4,7 @@ from __future__ import annotations
from datetime import datetime, timedelta from datetime import datetime, timedelta
import logging import logging
from typing import TYPE_CHECKING, Any from typing import TYPE_CHECKING
from fyta_cli.fyta_connector import FytaConnector from fyta_cli.fyta_connector import FytaConnector
from fyta_cli.fyta_exceptions import ( from fyta_cli.fyta_exceptions import (
@ -13,6 +13,7 @@ from fyta_cli.fyta_exceptions import (
FytaPasswordError, FytaPasswordError,
FytaPlantError, FytaPlantError,
) )
from fyta_cli.fyta_models import Plant
from homeassistant.const import CONF_ACCESS_TOKEN from homeassistant.const import CONF_ACCESS_TOKEN
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -27,7 +28,7 @@ if TYPE_CHECKING:
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
class FytaCoordinator(DataUpdateCoordinator[dict[int, dict[str, Any]]]): class FytaCoordinator(DataUpdateCoordinator[dict[int, Plant]]):
"""Fyta custom coordinator.""" """Fyta custom coordinator."""
config_entry: FytaConfigEntry config_entry: FytaConfigEntry
@ -44,7 +45,7 @@ class FytaCoordinator(DataUpdateCoordinator[dict[int, dict[str, Any]]]):
async def _async_update_data( async def _async_update_data(
self, self,
) -> dict[int, dict[str, Any]]: ) -> dict[int, Plant]:
"""Fetch data from API endpoint.""" """Fetch data from API endpoint."""
if ( if (
@ -60,7 +61,6 @@ class FytaCoordinator(DataUpdateCoordinator[dict[int, dict[str, Any]]]):
async def renew_authentication(self) -> bool: async def renew_authentication(self) -> bool:
"""Renew access token for FYTA API.""" """Renew access token for FYTA API."""
credentials: dict[str, Any] = {}
try: try:
credentials = await self.fyta.login() credentials = await self.fyta.login()
@ -70,8 +70,8 @@ class FytaCoordinator(DataUpdateCoordinator[dict[int, dict[str, Any]]]):
raise ConfigEntryAuthFailed from ex raise ConfigEntryAuthFailed from ex
new_config_entry = {**self.config_entry.data} new_config_entry = {**self.config_entry.data}
new_config_entry[CONF_ACCESS_TOKEN] = credentials[CONF_ACCESS_TOKEN] new_config_entry[CONF_ACCESS_TOKEN] = credentials.access_token
new_config_entry[CONF_EXPIRATION] = credentials[CONF_EXPIRATION].isoformat() new_config_entry[CONF_EXPIRATION] = credentials.expiration.isoformat()
self.hass.config_entries.async_update_entry( self.hass.config_entries.async_update_entry(
self.config_entry, data=new_config_entry self.config_entry, data=new_config_entry

View File

@ -25,5 +25,5 @@ async def async_get_config_entry_diagnostics(
return { return {
"config_entry": async_redact_data(config_entry.as_dict(), TO_REDACT), "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()},
} }

View File

@ -1,6 +1,6 @@
"""Entities for FYTA integration.""" """Entities for FYTA integration."""
from typing import Any from fyta_cli.fyta_models import Plant
from homeassistant.components.sensor import SensorEntityDescription from homeassistant.components.sensor import SensorEntityDescription
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
@ -32,13 +32,13 @@ class FytaPlantEntity(CoordinatorEntity[FytaCoordinator]):
manufacturer="Fyta", manufacturer="Fyta",
model="Plant", model="Plant",
identifiers={(DOMAIN, f"{entry.entry_id}-{plant_id}")}, identifiers={(DOMAIN, f"{entry.entry_id}-{plant_id}")},
name=self.plant.get("name"), name=self.plant.name,
sw_version=self.plant.get("sw_version"), sw_version=self.plant.sw_version,
) )
self.entity_description = description self.entity_description = description
@property @property
def plant(self) -> dict[str, Any]: def plant(self) -> Plant:
"""Get plant data.""" """Get plant data."""
return self.coordinator.data[self.plant_id] return self.coordinator.data[self.plant_id]

View File

@ -7,5 +7,5 @@
"integration_type": "hub", "integration_type": "hub",
"iot_class": "cloud_polling", "iot_class": "cloud_polling",
"quality_scale": "platinum", "quality_scale": "platinum",
"requirements": ["fyta_cli==0.4.1"] "requirements": ["fyta_cli==0.6.0"]
} }

View File

@ -7,7 +7,7 @@ from dataclasses import dataclass
from datetime import datetime from datetime import datetime
from typing import Final 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 ( from homeassistant.components.sensor import (
SensorDeviceClass, SensorDeviceClass,
@ -23,19 +23,18 @@ from homeassistant.const import (
) )
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from . import FytaConfigEntry from . import FytaConfigEntry
from .coordinator import FytaCoordinator from .coordinator import FytaCoordinator
from .entity import FytaPlantEntity from .entity import FytaPlantEntity
@dataclass(frozen=True) @dataclass(frozen=True, kw_only=True)
class FytaSensorEntityDescription(SensorEntityDescription): class FytaSensorEntityDescription(SensorEntityDescription):
"""Describes Fyta sensor entity.""" """Describes Fyta sensor entity."""
value_fn: Callable[[str | int | float | datetime], str | int | float | datetime] = ( value_fn: Callable[[Plant], StateType | datetime]
lambda value: value
)
PLANT_STATUS_LIST: list[str] = ["deleted", "doing_great", "need_attention", "no_sensor"] PLANT_STATUS_LIST: list[str] = ["deleted", "doing_great", "need_attention", "no_sensor"]
@ -48,63 +47,68 @@ PLANT_MEASUREMENT_STATUS_LIST: list[str] = [
"too_high", "too_high",
] ]
SENSORS: Final[list[FytaSensorEntityDescription]] = [ SENSORS: Final[list[FytaSensorEntityDescription]] = [
FytaSensorEntityDescription( FytaSensorEntityDescription(
key="scientific_name", key="scientific_name",
translation_key="scientific_name", translation_key="scientific_name",
value_fn=lambda plant: plant.scientific_name,
), ),
FytaSensorEntityDescription( FytaSensorEntityDescription(
key="status", key="status",
translation_key="plant_status", translation_key="plant_status",
device_class=SensorDeviceClass.ENUM, device_class=SensorDeviceClass.ENUM,
options=PLANT_STATUS_LIST, options=PLANT_STATUS_LIST,
value_fn=PLANT_STATUS.get, value_fn=lambda plant: plant.status.name.lower(),
), ),
FytaSensorEntityDescription( FytaSensorEntityDescription(
key="temperature_status", key="temperature_status",
translation_key="temperature_status", translation_key="temperature_status",
device_class=SensorDeviceClass.ENUM, device_class=SensorDeviceClass.ENUM,
options=PLANT_MEASUREMENT_STATUS_LIST, options=PLANT_MEASUREMENT_STATUS_LIST,
value_fn=PLANT_MEASUREMENT_STATUS.get, value_fn=lambda plant: plant.temperature_status.name.lower(),
), ),
FytaSensorEntityDescription( FytaSensorEntityDescription(
key="light_status", key="light_status",
translation_key="light_status", translation_key="light_status",
device_class=SensorDeviceClass.ENUM, device_class=SensorDeviceClass.ENUM,
options=PLANT_MEASUREMENT_STATUS_LIST, options=PLANT_MEASUREMENT_STATUS_LIST,
value_fn=PLANT_MEASUREMENT_STATUS.get, value_fn=lambda plant: plant.light_status.name.lower(),
), ),
FytaSensorEntityDescription( FytaSensorEntityDescription(
key="moisture_status", key="moisture_status",
translation_key="moisture_status", translation_key="moisture_status",
device_class=SensorDeviceClass.ENUM, device_class=SensorDeviceClass.ENUM,
options=PLANT_MEASUREMENT_STATUS_LIST, options=PLANT_MEASUREMENT_STATUS_LIST,
value_fn=PLANT_MEASUREMENT_STATUS.get, value_fn=lambda plant: plant.moisture_status.name.lower(),
), ),
FytaSensorEntityDescription( FytaSensorEntityDescription(
key="salinity_status", key="salinity_status",
translation_key="salinity_status", translation_key="salinity_status",
device_class=SensorDeviceClass.ENUM, device_class=SensorDeviceClass.ENUM,
options=PLANT_MEASUREMENT_STATUS_LIST, options=PLANT_MEASUREMENT_STATUS_LIST,
value_fn=PLANT_MEASUREMENT_STATUS.get, value_fn=lambda plant: plant.salinity_status.name.lower(),
), ),
FytaSensorEntityDescription( FytaSensorEntityDescription(
key="temperature", key="temperature",
native_unit_of_measurement=UnitOfTemperature.CELSIUS, native_unit_of_measurement=UnitOfTemperature.CELSIUS,
device_class=SensorDeviceClass.TEMPERATURE, device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda plant: plant.temperature,
), ),
FytaSensorEntityDescription( FytaSensorEntityDescription(
key="light", key="light",
translation_key="light", translation_key="light",
native_unit_of_measurement="μmol/s⋅m²", native_unit_of_measurement="μmol/s⋅m²",
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda plant: plant.light,
), ),
FytaSensorEntityDescription( FytaSensorEntityDescription(
key="moisture", key="moisture",
native_unit_of_measurement=PERCENTAGE, native_unit_of_measurement=PERCENTAGE,
device_class=SensorDeviceClass.MOISTURE, device_class=SensorDeviceClass.MOISTURE,
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda plant: plant.moisture,
), ),
FytaSensorEntityDescription( FytaSensorEntityDescription(
key="salinity", key="salinity",
@ -112,11 +116,13 @@ SENSORS: Final[list[FytaSensorEntityDescription]] = [
native_unit_of_measurement=UnitOfConductivity.MILLISIEMENS, native_unit_of_measurement=UnitOfConductivity.MILLISIEMENS,
device_class=SensorDeviceClass.CONDUCTIVITY, device_class=SensorDeviceClass.CONDUCTIVITY,
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda plant: plant.salinity,
), ),
FytaSensorEntityDescription( FytaSensorEntityDescription(
key="ph", key="ph",
device_class=SensorDeviceClass.PH, device_class=SensorDeviceClass.PH,
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda plant: plant.ph,
), ),
FytaSensorEntityDescription( FytaSensorEntityDescription(
key="battery_level", key="battery_level",
@ -124,6 +130,7 @@ SENSORS: Final[list[FytaSensorEntityDescription]] = [
device_class=SensorDeviceClass.BATTERY, device_class=SensorDeviceClass.BATTERY,
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC, 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) FytaPlantSensor(coordinator, entry, sensor, plant_id)
for plant_id in coordinator.fyta.plant_list for plant_id in coordinator.fyta.plant_list
for sensor in SENSORS 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) async_add_entities(plant_entities)
@ -150,8 +157,7 @@ class FytaPlantSensor(FytaPlantEntity, SensorEntity):
entity_description: FytaSensorEntityDescription entity_description: FytaSensorEntityDescription
@property @property
def native_value(self) -> str | int | float | datetime: def native_value(self) -> StateType | datetime:
"""Return the state for this sensor.""" """Return the state for this sensor."""
val = self.plant[self.entity_description.key] return self.entity_description.value_fn(self.plant)
return self.entity_description.value_fn(val)

View File

@ -1726,6 +1726,16 @@ disallow_untyped_defs = true
warn_return_any = true warn_return_any = true
warn_unreachable = 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.*] [mypy-homeassistant.components.generic_hygrostat.*]
check_untyped_defs = true check_untyped_defs = true
disallow_incomplete_defs = true disallow_incomplete_defs = true

View File

@ -921,7 +921,7 @@ freesms==0.2.0
fritzconnection[qr]==1.13.2 fritzconnection[qr]==1.13.2
# homeassistant.components.fyta # homeassistant.components.fyta
fyta_cli==0.4.1 fyta_cli==0.6.0
# homeassistant.components.google_translate # homeassistant.components.google_translate
gTTS==2.2.4 gTTS==2.2.4

View File

@ -774,7 +774,7 @@ freebox-api==1.1.0
fritzconnection[qr]==1.13.2 fritzconnection[qr]==1.13.2
# homeassistant.components.fyta # homeassistant.components.fyta
fyta_cli==0.4.1 fyta_cli==0.6.0
# homeassistant.components.google_translate # homeassistant.components.google_translate
gTTS==2.2.4 gTTS==2.2.4

View File

@ -4,6 +4,7 @@ from collections.abc import Generator
from datetime import UTC, datetime from datetime import UTC, datetime
from unittest.mock import AsyncMock, patch from unittest.mock import AsyncMock, patch
from fyta_cli.fyta_models import Credentials, Plant
import pytest import pytest
from homeassistant.components.fyta.const import CONF_EXPIRATION, DOMAIN as FYTA_DOMAIN 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(): def mock_fyta_connector():
"""Build a fixture for the Fyta API that connects successfully and returns one device.""" """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 = AsyncMock()
mock_fyta_connector.expiration = datetime.fromisoformat(EXPIRATION).replace( mock_fyta_connector.expiration = datetime.fromisoformat(EXPIRATION).replace(
tzinfo=UTC tzinfo=UTC
) )
mock_fyta_connector.client = AsyncMock(autospec=True) mock_fyta_connector.client = AsyncMock(autospec=True)
mock_fyta_connector.update_all_plants.return_value = load_json_object_fixture( mock_fyta_connector.update_all_plants.return_value = plants
"plant_status.json", FYTA_DOMAIN mock_fyta_connector.plant_list = {
) 0: "Gummibaum",
mock_fyta_connector.plant_list = load_json_object_fixture( 1: "Kakaobaum",
"plant_list.json", FYTA_DOMAIN }
)
mock_fyta_connector.login = AsyncMock( mock_fyta_connector.login = AsyncMock(
return_value={ return_value=Credentials(
CONF_ACCESS_TOKEN: ACCESS_TOKEN, access_token=ACCESS_TOKEN,
CONF_EXPIRATION: datetime.fromisoformat(EXPIRATION).replace(tzinfo=UTC), expiration=datetime.fromisoformat(EXPIRATION).replace(tzinfo=UTC),
} )
) )
with ( with (
patch( patch(

View File

@ -1,4 +0,0 @@
{
"0": "Gummibaum",
"1": "Kakaobaum"
}

View File

@ -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"
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -23,16 +23,50 @@
}), }),
'plant_data': dict({ 'plant_data': dict({
'0': 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', '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', 'scientific_name': 'Ficus elastica',
'status': 1, 'sensor_available': True,
'status': 3,
'sw_version': '1.0', 'sw_version': '1.0',
'temperature': 25.2,
'temperature_status': 3,
}), }),
'1': dict({ '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', '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', 'scientific_name': 'Theobroma cacao',
'status': 2, 'sensor_available': True,
'status': 3,
'sw_version': '1.0', 'sw_version': '1.0',
'temperature': 25.2,
'temperature_status': 3,
}), }),
}), }),
}) })

File diff suppressed because it is too large Load Diff