99else :
1010 from typing_extensions import Self
1111
12- from pydantic . v1 import BaseModel , Field , ValidationError
12+ from pydantic import BaseModel , ConfigDict , Field , ValidationError
1313from xmltodict import parse as xml_parse
1414
1515from ..exceptions import OmniParsingException
3737class OmniBase (BaseModel ):
3838 _sub_devices : set [str ] | None = None
3939 system_id : int = Field (alias = "System-Id" )
40- name : str | None = Field (alias = "Name" )
41- bow_id : int | None
40+ name : str | None = Field (alias = "Name" , default = None )
41+ bow_id : int | None = None
4242
4343 def without_subdevices (self ) -> Self :
44- return self .copy (exclude = self ._sub_devices )
44+ data = self .model_dump (exclude = self ._sub_devices , round_trip = True )
45+ data = {** data , ** {}}
46+ copied = self .model_validate (data )
47+ _LOGGER .debug ("without_subdevices: original=%s, copied=%s" , self , copied )
48+ return copied
49+ # return self.copy(exclude=self._sub_devices)
4550
4651 def propagate_bow_id (self , bow_id : int | None ) -> None :
4752 # First we set our own bow_id
@@ -63,6 +68,8 @@ def propagate_bow_id(self, bow_id: int | None) -> None:
6368
6469
6570class MSPSystem (BaseModel ):
71+ model_config = ConfigDict (from_attributes = True )
72+
6673 omni_type : OmniType = OmniType .SYSTEM
6774 vsp_speed_format : Literal ["RPM" , "Percent" ] = Field (alias = "Msp-Vsp-Speed-Format" )
6875 units : Literal ["Standard" , "Metric" ] = Field (alias = "Units" )
@@ -116,7 +123,7 @@ class MSPHeaterEquip(OmniBase):
116123 enabled : Literal ["yes" , "no" ] = Field (alias = "Enabled" )
117124 min_filter_speed : int = Field (alias = "Min-Speed-For-Operation" )
118125 sensor_id : int = Field (alias = "Sensor-System-Id" )
119- supports_cooling : Literal ["yes" , "no" ] | None = Field (alias = "SupportsCooling" )
126+ supports_cooling : Literal ["yes" , "no" ] | None = Field (alias = "SupportsCooling" , default = None )
120127
121128
122129# This is the entry for the VirtualHeater, it does not use OmniBase because it has no name attribute
@@ -126,18 +133,18 @@ class MSPVirtualHeater(OmniBase):
126133 omni_type : OmniType = OmniType .VIRT_HEATER
127134 enabled : Literal ["yes" , "no" ] = Field (alias = "Enabled" )
128135 set_point : int = Field (alias = "Current-Set-Point" )
129- solar_set_point : int | None = Field (alias = "SolarSetPoint" )
136+ solar_set_point : int | None = Field (alias = "SolarSetPoint" , default = None )
130137 max_temp : int = Field (alias = "Max-Settable-Water-Temp" )
131138 min_temp : int = Field (alias = "Min-Settable-Water-Temp" )
132- heater_equipment : list [MSPHeaterEquip ] | None
139+ heater_equipment : list [MSPHeaterEquip ] | None = None
133140
134141 def __init__ (self , ** data : Any ) -> None :
135142 super ().__init__ (** data )
136143
137144 # The heater equipment are nested down inside a list of "Operations", which also includes non Heater-Equipment items. We need to
138145 # first filter down to just the heater equipment items, then populate our self.heater_equipment with parsed versions of those items.
139146 heater_equip_data = [op [OmniType .HEATER_EQUIP ] for op in data .get ("Operation" , {}) if OmniType .HEATER_EQUIP in op ]
140- self .heater_equipment = [MSPHeaterEquip .parse_obj (equip ) for equip in heater_equip_data ]
147+ self .heater_equipment = [MSPHeaterEquip .model_validate (equip ) for equip in heater_equip_data ]
141148
142149
143150class MSPChlorinatorEquip (OmniBase ):
@@ -163,7 +170,9 @@ def __init__(self, **data: Any) -> None:
163170 # The heater equipment are nested down inside a list of "Operations", which also includes non Heater-Equipment items. We need to
164171 # first filter down to just the heater equipment items, then populate our self.heater_equipment with parsed versions of those items.
165172 chlorinator_equip_data = [op for op in data .get ("Operation" , {}) if OmniType .CHLORINATOR_EQUIP in op ][0 ]
166- self .chlorinator_equipment = [MSPChlorinatorEquip .parse_obj (equip ) for equip in chlorinator_equip_data [OmniType .CHLORINATOR_EQUIP ]]
173+ self .chlorinator_equipment = [
174+ MSPChlorinatorEquip .model_validate (equip ) for equip in chlorinator_equip_data [OmniType .CHLORINATOR_EQUIP ]
175+ ]
167176
168177
169178class MSPCSAD (OmniBase ):
@@ -185,8 +194,8 @@ class MSPCSAD(OmniBase):
185194class MSPColorLogicLight (OmniBase ):
186195 omni_type : OmniType = OmniType .CL_LIGHT
187196 type : ColorLogicLightType | str = Field (alias = "Type" )
188- v2_active : Literal ["yes" , "no" ] | None = Field (alias = "V2-Active" )
189- effects : list [ColorLogicShow ] | None
197+ v2_active : Literal ["yes" , "no" ] | None = Field (alias = "V2-Active" , default = None )
198+ effects : list [ColorLogicShow ] | None = None
190199
191200 def __init__ (self , ** data : Any ) -> None :
192201 super ().__init__ (** data )
@@ -199,14 +208,14 @@ class MSPBoW(OmniBase):
199208 omni_type : OmniType = OmniType .BOW
200209 type : BodyOfWaterType | str = Field (alias = "Type" )
201210 supports_spillover : Literal ["yes" , "no" ] = Field (alias = "Supports-Spillover" )
202- filter : list [MSPFilter ] | None = Field (alias = "Filter" )
203- relay : list [MSPRelay ] | None = Field (alias = "Relay" )
204- heater : MSPVirtualHeater | None = Field (alias = "Heater" )
205- sensor : list [MSPSensor ] | None = Field (alias = "Sensor" )
206- colorlogic_light : list [MSPColorLogicLight ] | None = Field (alias = "ColorLogic-Light" )
207- pump : list [MSPPump ] | None = Field (alias = "Pump" )
208- chlorinator : MSPChlorinator | None = Field (alias = "Chlorinator" )
209- csad : list [MSPCSAD ] | None = Field (alias = "CSAD" )
211+ filter : list [MSPFilter ] | None = Field (alias = "Filter" , default = None )
212+ relay : list [MSPRelay ] | None = Field (alias = "Relay" , default = None )
213+ heater : MSPVirtualHeater | None = Field (alias = "Heater" , default = None )
214+ sensor : list [MSPSensor ] | None = Field (alias = "Sensor" , default = None )
215+ colorlogic_light : list [MSPColorLogicLight ] | None = Field (alias = "ColorLogic-Light" , default = None )
216+ pump : list [MSPPump ] | None = Field (alias = "Pump" , default = None )
217+ chlorinator : MSPChlorinator | None = Field (alias = "Chlorinator" , default = None )
218+ csad : list [MSPCSAD ] | None = Field (alias = "CSAD" , default = None )
210219
211220 # We override the __init__ here so that we can trigger the propagation of the bow_id down to all of it's sub devices after the bow
212221 # itself is initialized
@@ -219,16 +228,16 @@ class MSPBackyard(OmniBase):
219228 _sub_devices = {"sensor" , "bow" , "colorlogic_light" , "relay" }
220229
221230 omni_type : OmniType = OmniType .BACKYARD
222- sensor : list [MSPSensor ] | None = Field (alias = "Sensor" )
223- bow : list [MSPBoW ] | None = Field (alias = "Body-of-water" )
224- relay : list [MSPRelay ] | None = Field (alias = "Relay" )
225- colorlogic_light : list [MSPColorLogicLight ] | None = Field (alias = "ColorLogic-Light" )
231+ sensor : list [MSPSensor ] | None = Field (alias = "Sensor" , default = None )
232+ bow : list [MSPBoW ] | None = Field (alias = "Body-of-water" , default = None )
233+ relay : list [MSPRelay ] | None = Field (alias = "Relay" , default = None )
234+ colorlogic_light : list [MSPColorLogicLight ] | None = Field (alias = "ColorLogic-Light" , default = None )
226235
227236
228237class MSPSchedule (OmniBase ):
229238 omni_type : OmniType = OmniType .SCHEDULE
230239 system_id : int = Field (alias = "schedule-system-id" )
231- bow_id : int = Field (alias = "bow-system-id" )
240+ bow_id : int | None = Field (alias = "bow-system-id" , default = None )
232241 equipment_id : int = Field (alias = "equipment-id" )
233242 enabled : bool = Field ()
234243
@@ -239,12 +248,11 @@ class MSPSchedule(OmniBase):
239248
240249
241250class MSPConfig (BaseModel ):
251+ model_config = ConfigDict (from_attributes = True )
252+
242253 system : MSPSystem = Field (alias = "System" )
243254 backyard : MSPBackyard = Field (alias = "Backyard" )
244255
245- class Config :
246- orm_mode = True
247-
248256 @staticmethod
249257 def load_xml (xml : str ) -> MSPConfig :
250258 data = xml_parse (
@@ -266,6 +274,6 @@ def load_xml(xml: str) -> MSPConfig:
266274 ),
267275 )
268276 try :
269- return MSPConfig .parse_obj (data ["MSPConfig" ])
277+ return MSPConfig .model_validate (data ["MSPConfig" ], from_attributes = True )
270278 except ValidationError as exc :
271279 raise OmniParsingException (f"Failed to parse MSP Configuration: { exc } " ) from exc
0 commit comments