1 """Diagnostics support for Enphase Envoy."""
3 from __future__
import annotations
6 from typing
import TYPE_CHECKING, Any
8 from attr
import asdict
9 from pyenphase.envoy
import Envoy
10 from pyenphase.exceptions
import EnvoyError
25 from .const
import OPTION_DIAGNOSTICS_INCLUDE_FIXTURES
26 from .coordinator
import EnphaseConfigEntry
29 CLEAN_TEXT =
"<<envoyserial>>"
43 """Collect Envoy endpoints to use for test fixture set."""
44 fixture_data: dict[str, Any] = {}
48 "/api/v1/production/inverters",
50 "/production.json?details=1",
52 "/ivp/ensemble/power",
53 "/ivp/ensemble/inventory",
54 "/ivp/ensemble/dry_contacts",
55 "/ivp/ensemble/status",
56 "/ivp/ensemble/secctrl",
57 "/ivp/ss/dry_contact_settings",
60 "/ivp/ss/gen_schedule",
62 "/ivp/ss/pel_settings",
63 "/ivp/ensemble/generator",
65 "/ivp/meters/readings",
68 for end_point
in end_points:
69 response = await envoy.request(end_point)
70 fixture_data[end_point] = response.text.replace(
"\n",
"").replace(
75 "headers":
dict(response.headers.items()),
76 "code": response.status_code,
83 hass: HomeAssistant, entry: EnphaseConfigEntry
85 """Return diagnostics for a config entry."""
86 coordinator = entry.runtime_data
89 assert coordinator.envoy.data
90 envoy_data = coordinator.envoy.data
91 envoy = coordinator.envoy
93 device_registry = dr.async_get(hass)
94 entity_registry = er.async_get(hass)
98 for device
in dr.async_entries_for_config_entry(device_registry, entry.entry_id):
100 for entity
in er.async_entries_for_device(
101 entity_registry, device_id=device.id, include_disabled_entities=
True
104 if state := hass.states.get(entity.entity_id):
105 state_dict =
dict(state.as_dict())
106 state_dict.pop(
"context",
None)
107 entity_dict = asdict(entity)
108 entity_dict.pop(
"_cache",
None)
109 entities.append({
"entity": entity_dict,
"state": state_dict})
110 device_dict = asdict(device)
111 device_dict.pop(
"_cache",
None)
112 device_entities.append({
"device": device_dict,
"entities": entities})
115 old_serial = coordinator.envoy_serial_number
117 coordinator_data = copy.deepcopy(coordinator.data)
118 coordinator_data_cleaned =
json_dumps(coordinator_data).replace(
119 old_serial, CLEAN_TEXT
122 device_entities_cleaned =
json_dumps(device_entities).replace(
123 old_serial, CLEAN_TEXT
126 envoy_model: dict[str, Any] = {
127 "encharge_inventory": envoy_data.encharge_inventory,
128 "encharge_power": envoy_data.encharge_power,
129 "encharge_aggregate": envoy_data.encharge_aggregate,
130 "enpower": envoy_data.enpower,
131 "system_consumption": envoy_data.system_consumption,
132 "system_production": envoy_data.system_production,
133 "system_consumption_phases": envoy_data.system_consumption_phases,
134 "system_production_phases": envoy_data.system_production_phases,
135 "ctmeter_production": envoy_data.ctmeter_production,
136 "ctmeter_consumption": envoy_data.ctmeter_consumption,
137 "ctmeter_storage": envoy_data.ctmeter_storage,
138 "ctmeter_production_phases": envoy_data.ctmeter_production_phases,
139 "ctmeter_consumption_phases": envoy_data.ctmeter_consumption_phases,
140 "ctmeter_storage_phases": envoy_data.ctmeter_storage_phases,
141 "dry_contact_status": envoy_data.dry_contact_status,
142 "dry_contact_settings": envoy_data.dry_contact_settings,
143 "inverters": envoy_data.inverters,
144 "tariff": envoy_data.tariff,
147 envoy_properties: dict[str, Any] = {
148 "envoy_firmware": envoy.firmware,
149 "part_number": envoy.part_number,
150 "envoy_model": envoy.envoy_model,
151 "supported_features": [feature.name
for feature
in envoy.supported_features],
152 "phase_mode": envoy.phase_mode,
153 "phase_count": envoy.phase_count,
154 "active_phasecount": envoy.active_phase_count,
155 "ct_count": envoy.ct_meter_count,
156 "ct_consumption_meter": envoy.consumption_meter_type,
157 "ct_production_meter": envoy.production_meter_type,
158 "ct_storage_meter": envoy.storage_meter_type,
161 fixture_data: dict[str, Any] = {}
162 if entry.options.get(OPTION_DIAGNOSTICS_INCLUDE_FIXTURES,
False):
165 except EnvoyError
as err:
166 fixture_data[
"Error"] = repr(err)
168 diagnostic_data: dict[str, Any] = {
170 "envoy_properties": envoy_properties,
171 "raw_data":
json_loads(coordinator_data_cleaned),
172 "envoy_model_data": envoy_model,
173 "envoy_entities_by_device":
json_loads(device_entities_cleaned),
174 "fixtures": fixture_data,
177 return diagnostic_data
dict async_redact_data(Mapping data, Iterable[Any] to_redact)
dict[str, Any] async_get_config_entry_diagnostics(HomeAssistant hass, EnphaseConfigEntry entry)
dict[str, Any] _get_fixture_collection(Envoy envoy, str serial)