Skip to content

Commit

Permalink
Merge pull request #1 from bacherd/move-functions-to-root
Browse files Browse the repository at this point in the history
Move functions to root level
  • Loading branch information
bacherd authored Jul 24, 2023
2 parents e29ea47 + dc5ab2b commit cfe75df
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 86 deletions.
3 changes: 2 additions & 1 deletion test/resources/stubs/module-definition-test.json
Original file line number Diff line number Diff line change
Expand Up @@ -386,5 +386,6 @@
},
"functions": []
}
}
},
"functions": {}
}
3 changes: 2 additions & 1 deletion test/resources/stubs/test_project-ets4.json
Original file line number Diff line number Diff line change
Expand Up @@ -311,5 +311,6 @@
},
"functions": []
}
}
},
"functions": {}
}
48 changes: 25 additions & 23 deletions test/resources/stubs/testprojekt-ets6-functions.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,33 +97,35 @@
"devices": [],
"spaces": {},
"functions": [
{
"identifier": "P-05C0-0_F-1",
"name": "LivingroomLight",
"function_type": "FT-1",
"usage_text": "switchable light",
"project_uid": 11,
"group_addresses": [
{
"identifier": "P-05C0-0_GF-1",
"name": "",
"role": "SwitchOnOff",
"address": "0/0/1",
"project_uid": 15
},
{
"identifier": "P-05C0-0_GF-2",
"name": "",
"role": "InfoOnOff",
"address": "0/0/2",
"project_uid": 17
}
]
}
"F-1"
]
}
},
"functions": []
}
},
"functions": {
"F-1": {
"function_type": "FT-1",
"group_addresses": {
"0/0/1": {
"address": "0/0/1",
"name": "",
"project_uid": 15,
"role": "SwitchOnOff"
},
"0/0/2": {
"address": "0/0/2",
"name": "",
"project_uid": 17,
"role": "InfoOnOff"
}
},
"identifier": "F-1",
"name": "LivingroomLight",
"project_uid": 11,
"space_id": "P-05C0-0_BP-2",
"usage_text": "switchable light"
}
}
}
3 changes: 2 additions & 1 deletion test/resources/stubs/xknx_test_project.json
Original file line number Diff line number Diff line change
Expand Up @@ -672,5 +672,6 @@
"spaces": {},
"functions": []
}
}
},
"functions": {}
}
63 changes: 41 additions & 22 deletions xknxproject/loader/project_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,14 @@ def load(
list[DeviceInstance],
list[XMLSpace],
XMLProjectInformation,
list[XMLFunction],
]:
"""Load topology mappings."""
areas: list[XMLArea] = []
devices: list[DeviceInstance] = []
group_address_list: list[XMLGroupAddress] = []
spaces: list[XMLSpace] = []
functions: list[XMLFunction] = []

with knx_proj_contents.open_project_0() as project_0_file:
tree = ElementTree.parse(project_0_file)
Expand Down Expand Up @@ -68,19 +70,35 @@ def load(
knx_proj_contents,
devices,
space_usage_names,
function_type_names,
group_address_list,
)
for location_element in tree.findall(
f"{{*}}Project/{{*}}Installations/{{*}}Installation/{{*}}{element_name}"
):
spaces.extend(location_loader.load(location_element=location_element))
spaces.extend(
location_loader.load(
location_element=location_element, functions=functions
)
)

with knx_proj_contents.open_project_meta() as project_file:
tree = ElementTree.parse(project_file)
project_info = load_project_info(tree)

return group_address_list, areas, devices, spaces, project_info
for function in functions:
function.usage_text = (
function_type_names.get(function.function_type, "")
if function.function_type
else ""
)

for group_address in function.group_addresses:
group_address.address = [
g
for g in group_address_list
if g.identifier == group_address.ref_id
][0].address

return group_address_list, areas, devices, spaces, project_info, functions


class _GroupAddressLoader:
Expand Down Expand Up @@ -242,8 +260,6 @@ def __init__(
knx_proj_contents: KNXProjContents,
devices: list[DeviceInstance],
space_usage_names: dict[str, str],
function_type_names: dict[str, str],
group_address_list: list[XMLGroupAddress],
):
"""Initialize the LocationLoader."""
self._element_name = (
Expand All @@ -253,17 +269,19 @@ def __init__(
device.identifier: device.individual_address for device in devices
}
self.space_usage_names = space_usage_names
self.function_type_names = function_type_names
self.group_address_list = group_address_list

def load(self, location_element: ElementTree.Element) -> list[XMLSpace]:
def load(
self, location_element: ElementTree.Element, functions: list[XMLFunction]
) -> list[XMLSpace]:
"""Load Location mappings."""
return [
self.parse_space(space)
self.parse_space(space, functions)
for space in location_element.findall(f"{{*}}{self._element_name}")
]

def parse_space(self, node: ElementTree.Element) -> XMLSpace:
def parse_space(
self, node: ElementTree.Element, functions: list[XMLFunction]
) -> XMLSpace:
"""Parse a space from the document."""
usage_id = node.get("Usage")
usage_text = self.space_usage_names.get(usage_id, "") if usage_id else ""
Expand All @@ -285,45 +303,46 @@ def parse_space(self, node: ElementTree.Element) -> XMLSpace:
for sub_node in node:
if sub_node.tag.endswith(self._element_name):
# recursively call parse space since this can be nested for an unbound time in the XSD
space.spaces.append(self.parse_space(sub_node))
space.spaces.append(self.parse_space(sub_node, functions))
elif sub_node.tag.endswith("DeviceInstanceRef"):
if individual_address := self.devices.get(sub_node.get("RefId", "")):
space.devices.append(individual_address)
elif sub_node.tag.endswith("Function"):
space.functions.append(self.parse_functions(sub_node))
function = self.parse_functions(sub_node)
function.space_id = space.identifier
functions.append(function)
space.functions.append(function.identifier)

return space

def parse_functions(self, node: ElementTree.Element) -> XMLFunction:
"""Parse a functions from the document."""
identifier = node.get("Id", "").split("_")[1]
project_uid = node.get("Puid")
function_type = node.get("Type", "")
usage_text = (
self.function_type_names.get(function_type, "") if function_type else ""
)

functions: XMLFunction = XMLFunction(
identifier=node.get("Id"), # type: ignore[arg-type]
identifier=identifier,
name=node.get("Name"), # type: ignore[arg-type]
function_type=function_type,
project_uid=int(project_uid) if project_uid else None,
group_addresses=[],
usage_text=usage_text,
usage_text="",
space_id="",
)

for sub_node in node:
if sub_node.tag.endswith("GroupAddressRef"):
project_uid = sub_node.get("Puid")
ref_id = sub_node.get("RefId", "").split("_")[1]
address = [
g for g in self.group_address_list if g.identifier == ref_id
][0].address

group_address_ref: XMLGroupAddressRef = XMLGroupAddressRef(
ref_id=ref_id,
identifier=sub_node.get("Id"), # type: ignore[arg-type]
name=sub_node.get("Name"), # type: ignore[arg-type]
role=sub_node.get("Role", ""),
address=address,
project_uid=int(project_uid) if project_uid else None,
address="",
)
functions.group_addresses.append(group_address_ref)

Expand Down
15 changes: 8 additions & 7 deletions xknxproject/models/knxproject.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,28 +92,28 @@ class Space(TypedDict):
project_uid: int | None
devices: list[str]
spaces: dict[str, Space]
functions: list[Function]
functions: list[str]


class Function(TypedDict):
"""Function typed dict."""

function_type: str
group_addresses: dict[str, GroupAddressRef]
identifier: str
name: str
function_type: str
usage_text: str
project_uid: int | None
group_addresses: list[GroupAddressRef]
space_id: str
usage_text: str


class GroupAddressRef(TypedDict):
"""GroupAddressRef typed dict."""

identifier: str
name: str
role: str
address: str
name: str
project_uid: int | None
role: str


class ProjectInfo(TypedDict):
Expand All @@ -140,3 +140,4 @@ class KNXProject(TypedDict):
topology: dict[str, Area]
locations: dict[str, Space]
group_addresses: dict[str, GroupAddress]
functions: dict[str, Function]
14 changes: 8 additions & 6 deletions xknxproject/models/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,30 +273,32 @@ class XMLSpace:
project_uid: int | None
spaces: list[XMLSpace]
devices: list[str] # [DeviceInstance.individual_address]
functions: list[XMLFunction]
functions: list[str]


@dataclass
class XMLFunction:
"""A functions in the space XML."""

function_type: str
group_addresses: list[XMLGroupAddressRef]
identifier: str
name: str
function_type: str
usage_text: str
project_uid: int | None
group_addresses: list[XMLGroupAddressRef]
space_id: str
usage_text: str


@dataclass
class XMLGroupAddressRef:
"""A GroupAddressRef in the functions XML."""

address: str
identifier: str
name: str
role: str
address: str
project_uid: int | None
ref_id: str
role: str


@dataclass
Expand Down
Loading

0 comments on commit cfe75df

Please sign in to comment.