|
1 | 1 | from __future__ import annotations |
2 | 2 |
|
3 | | -from pydantic import BaseModel, ConfigDict, Field |
4 | | -from xmltodict import parse as xml_parse |
| 3 | +from pydantic import ConfigDict |
| 4 | +from pydantic_xml import BaseXmlModel, attr, element, wrapped |
5 | 5 |
|
| 6 | +from .const import XML_NS |
6 | 7 |
|
7 | | -class FilterDiagnosticsParameter(BaseModel): |
8 | | - model_config = ConfigDict(from_attributes=True) |
| 8 | +# Example Filter Diagnostics XML: |
| 9 | +# |
| 10 | +# <?xml version="1.0" encoding="UTF-8" ?> |
| 11 | +# <Response xmlns="http://nextgen.hayward.com/api"> |
| 12 | +# <Name>GetUIFilterDiagnosticInfoRsp</Name> |
| 13 | +# <Parameters> |
| 14 | +# <Parameter name="PoolID" dataType="int">7</Parameter> |
| 15 | +# <Parameter name="EquipmentID" dataType="int">8</Parameter> |
| 16 | +# <Parameter name="PowerLSB" dataType="byte">133</Parameter> |
| 17 | +# <Parameter name="PowerMSB" dataType="byte">4</Parameter> |
| 18 | +# <Parameter name="ErrorStatus" dataType="byte">0</Parameter> |
| 19 | +# <Parameter name="DisplayFWRevisionB1" dataType="byte">49</Parameter> |
| 20 | +# <Parameter name="DisplayFWRevisionB2" dataType="byte">48</Parameter> |
| 21 | +# <Parameter name="DisplayFWRevisionB3" dataType="byte">49</Parameter> |
| 22 | +# <Parameter name="DisplayFWRevisionB4" dataType="byte">53</Parameter> |
| 23 | +# <Parameter name="DisplayFWRevisionB5" dataType="byte">32</Parameter> |
| 24 | +# <Parameter name="DisplayFWRevisionB6" dataType="byte">0</Parameter> |
| 25 | +# <Parameter name="DriveFWRevisionB1" dataType="byte">48</Parameter> |
| 26 | +# <Parameter name="DriveFWRevisionB2" dataType="byte">48</Parameter> |
| 27 | +# <Parameter name="DriveFWRevisionB3" dataType="byte">55</Parameter> |
| 28 | +# <Parameter name="DriveFWRevisionB4" dataType="byte">48</Parameter> |
| 29 | +# <Parameter name="DriveFWRevisionB5" dataType="byte">32</Parameter> |
| 30 | +# <Parameter name="DriveFWRevisionB6" dataType="byte">0</Parameter> |
| 31 | +# </Parameters> |
| 32 | +# </Response> |
9 | 33 |
|
10 | | - name: str = Field(alias="@name") |
11 | | - dataType: str = Field(alias="@dataType") |
12 | | - value: int = Field(alias="#text") |
13 | 34 |
|
| 35 | +class FilterDiagnosticsParameter(BaseXmlModel, tag="Parameter", ns="api", nsmap=XML_NS): |
| 36 | + """Individual diagnostic parameter with name, type, and value.""" |
14 | 37 |
|
15 | | -class FilterDiagnosticsParameters(BaseModel): |
16 | 38 | model_config = ConfigDict(from_attributes=True) |
17 | 39 |
|
18 | | - parameter: list[FilterDiagnosticsParameter] = Field(alias="Parameter") |
| 40 | + name: str = attr() |
| 41 | + data_type: str = attr(name="dataType") |
| 42 | + value: int |
| 43 | + |
19 | 44 |
|
| 45 | +class FilterDiagnostics(BaseXmlModel, tag="Response", ns="api", nsmap=XML_NS): |
| 46 | + """Filter diagnostics response containing diagnostic parameters. |
| 47 | +
|
| 48 | + The XML structure has a Parameters wrapper element containing Parameter children: |
| 49 | + <Response> |
| 50 | + <Name>FilterDiagnostics</Name> |
| 51 | + <Parameters> |
| 52 | + <Parameter name="..." dataType="...">value</Parameter> |
| 53 | + ... |
| 54 | + </Parameters> |
| 55 | + </Response> |
| 56 | + """ |
20 | 57 |
|
21 | | -class FilterDiagnostics(BaseModel): |
22 | 58 | model_config = ConfigDict(from_attributes=True) |
23 | 59 |
|
24 | | - name: str = Field(alias="Name") |
25 | | - # parameters: FilterDiagnosticsParameters = Field(alias="Parameters") |
26 | | - parameters: list[FilterDiagnosticsParameter] = Field(alias="Parameters") |
| 60 | + name: str = element(tag="Name") |
| 61 | + parameters: list[FilterDiagnosticsParameter] = wrapped("Parameters", element(tag="Parameter", default_factory=list)) |
27 | 62 |
|
28 | 63 | def get_param_by_name(self, name: str) -> int: |
| 64 | + """Get parameter value by name. |
| 65 | +
|
| 66 | + Args: |
| 67 | + name: Name of the parameter to retrieve |
| 68 | +
|
| 69 | + Returns: |
| 70 | + The integer value of the parameter |
| 71 | +
|
| 72 | + Raises: |
| 73 | + IndexError: If parameter name not found |
| 74 | + """ |
29 | 75 | return [param.value for param in self.parameters if param.name == name][0] |
30 | 76 |
|
31 | 77 | @staticmethod |
32 | 78 | def load_xml(xml: str) -> FilterDiagnostics: |
33 | | - data = xml_parse( |
34 | | - xml, |
35 | | - # Some things will be lists or not depending on if a pool has more than one of that piece of equipment. Here we are coercing |
36 | | - # everything that *could* be a list into a list to make the parsing more consistent. |
37 | | - force_list=("Parameter"), |
38 | | - ) |
39 | | - # The XML nests the Parameter entries under a Parameters entry, this is annoying to work with. Here we are adjusting the data to |
40 | | - # remove that extra level in the data |
41 | | - data["Response"]["Parameters"] = data["Response"]["Parameters"]["Parameter"] |
42 | | - return FilterDiagnostics.model_validate(data["Response"]) |
| 79 | + """Load filter diagnostics from XML string. |
| 80 | +
|
| 81 | + Args: |
| 82 | + xml: XML string containing filter diagnostics data |
| 83 | +
|
| 84 | + Returns: |
| 85 | + Parsed FilterDiagnostics instance |
| 86 | + """ |
| 87 | + return FilterDiagnostics.from_xml(xml) |
0 commit comments