Skip to content

Commit 36042fe

Browse files
authored
[DEV-835] ContactDetails and DirectionalCurrentRelay (#213)
Signed-off-by: Max Chesterfield <max.chesterfield@zepben.com>
1 parent a56c3bc commit 36042fe

82 files changed

Lines changed: 2430 additions & 262 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

changelog.md

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,32 @@
11
# Zepben Python SDK
22
## [1.2.0] - UNRELEASED
33
### Breaking Changes
4-
* None.
4+
* The following gRPC fields have been modified to support nulls (they were missed in v1.0.0):
5+
* `Document.created_date_time`
6+
* `Equipment.commissioned_date`
7+
* `MeasurementValue.time_stamp`
8+
* `RelayInfo.curve_setting`
9+
* `RelayInfo.reclose_fast`
510

611
### New Features
7-
* None.
12+
* Added the following new CIM classes:
13+
* `DateTimeInterval`, interval between two date and time points, where the interval includes the start time but excludes end time.
14+
* `ElectronicAddress`, electronic address information.
15+
* `TelephoneNumber`, telephone number.
16+
* Added the following new CIM extension classes:
17+
* `ContactDetails`, the details required to contact a person or company. These can be accessed/used via a `UsagePoint`.
18+
* `DirectionalCurrentRelay`, a directional current relay is a type of protective relay used in electrical power systems to detect the direction of current
19+
flow and operate only when the current exceeds a certain threshold in a specified direction.
20+
* Added new CIM extension enums:
21+
* `ContactMethodType`
22+
* `PolarizingQuantityType`
823

924
### Enhancements
10-
* None.
25+
* * `BaseService.contains` has been been expanded to support objects in addition to mRIDs.
26+
* `Agreement` now supports `validity_interval`, the date and time interval the agreement is valid (from going into effect to termination).
27+
* `StreetDetail` now supports extension `building_number`, the number of the building.
28+
* `TownDetail` now supports `country`, the name of the country.
29+
* `ngen()` now directly accepts `dict()`s and will return a generator of the `values()` or `None` if `collection is None`
1130

1231
### Fixes
1332
* Reordered the feeder equipment and direction assignment on database read to prevent parallel feeders from tracing back into the zone substation.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
{name = "Max Chesterfield", email = "max.chesterfield@zepben.com"}
2424
]
2525
dependencies = [
26-
"zepben.protobuf==1.0.0",
26+
"zepben.protobuf==1.1.0",
2727
"typing_extensions==4.14.1",
2828
"requests==2.32.5",
2929
"urllib3==2.5.0",

src/zepben/ewb/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424

2525
from zepben.ewb.model.cim.extensions.iec61968.assetinfo.relay_info import *
2626

27+
from zepben.ewb.model.cim.extensions.iec61968.common.contact_details import *
28+
from zepben.ewb.model.cim.extensions.iec61968.common.contact_method_type import *
29+
2730
from zepben.ewb.model.cim.extensions.iec61968.metering.pan_demand_reponse_function import *
2831

2932
from zepben.ewb.model.cim.extensions.iec61970.base.core.site import *
@@ -33,7 +36,9 @@
3336

3437
from zepben.ewb.model.cim.extensions.iec61970.base.generation.production.ev_charging_unit import *
3538

39+
from zepben.ewb.model.cim.extensions.iec61970.base.protection.directional_current_relay import *
3640
from zepben.ewb.model.cim.extensions.iec61970.base.protection.distance_relay import *
41+
from zepben.ewb.model.cim.extensions.iec61970.base.protection.polarizing_quantity_type import *
3742
from zepben.ewb.model.cim.extensions.iec61970.base.protection.power_direction_kind import *
3843
from zepben.ewb.model.cim.extensions.iec61970.base.protection.protection_kind import *
3944
from zepben.ewb.model.cim.extensions.iec61970.base.protection.protection_relay_function import *
@@ -73,12 +78,14 @@
7378

7479
from zepben.ewb.model.cim.iec61968.common.agreement import *
7580
from zepben.ewb.model.cim.iec61968.common.document import *
81+
from zepben.ewb.model.cim.iec61968.common.electronic_address import *
7682
from zepben.ewb.model.cim.iec61968.common.location import *
7783
from zepben.ewb.model.cim.iec61968.common.organisation import *
7884
from zepben.ewb.model.cim.iec61968.common.organisation_role import *
7985
from zepben.ewb.model.cim.iec61968.common.position_point import *
8086
from zepben.ewb.model.cim.iec61968.common.street_address import *
8187
from zepben.ewb.model.cim.iec61968.common.street_detail import *
88+
from zepben.ewb.model.cim.iec61968.common.telephone_number import *
8289
from zepben.ewb.model.cim.iec61968.common.town_detail import *
8390

8491
from zepben.ewb.model.cim.iec61968.customers.customer import *

src/zepben/ewb/database/sql/column.py

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
from enum import Enum
99

10-
from zepben.ewb.dataclassy import dataclass
10+
from dataclasses import dataclass
1111
from zepben.ewb.util import require
1212

1313

@@ -21,17 +21,33 @@ def sql(self):
2121
return self.value
2222

2323

24+
class Type(Enum):
25+
STRING = "TEXT"
26+
INTEGER = "INTEGER"
27+
DOUBLE = "NUMBER"
28+
BOOLEAN = "BOOLEAN"
29+
UUID = "TEXT"
30+
TIMESTAMP = "TEXT"
31+
BYTES = "BLOB"
32+
33+
2434
@dataclass(slots=True)
2535
class Column:
2636
query_index: int
2737
name: str
28-
type: str
38+
type: str | Type
39+
"""Deprecated, use `type` instead"""
2940
nullable: Nullable = Nullable.NONE
3041

31-
def __init__(self):
42+
def __post_init__(self):
3243
require(self.query_index >= 0, lambda: "You cannot use a negative query index.")
33-
require(not self.name.isspace() and self.name, lambda: "Column Name cannot be blank.")
34-
require(not self.type.isspace() and self.type, lambda: "Column Type cannot be blank.")
44+
if not isinstance(self.type, Type):
45+
DeprecationWarning("Passing strings directly to Column is being phased out, use the Type enum instead.")
46+
require(not self.name.isspace() and self.name, lambda: "Column Name cannot be blank.")
47+
require(not self.type.isspace() and self.type, lambda: "Column Type cannot be blank.")
48+
# FIXME: We should accept isinstance(self.type, Type) from here on.
3549

3650
def __str__(self):
51+
if isinstance(self.type, Type):
52+
return f"{self.name} {self.type.value} {self.nullable.sql}".rstrip()
3753
return f"{self.name} {self.type} {self.nullable.sql}".rstrip()

src/zepben/ewb/database/sql/sql_table.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88

99
from abc import abstractmethod, ABCMeta
1010
from operator import attrgetter
11-
from typing import List, Optional, Type, Any, Generator
11+
from typing import List, Optional, Any, Generator
12+
from zepben.ewb.database.sql.column import Type
1213

1314
from zepben.ewb.database.sql.column import Column, Nullable
1415

@@ -136,7 +137,7 @@ def _build_column_set(clazz: Type[Any], instance: SqlTable) -> Generator[Column,
136137

137138
yield from sorted(cols, key=attrgetter('query_index'))
138139

139-
def _create_column(self, name: str, type_: str, nullable: Nullable = Nullable.NONE) -> Column:
140+
def _create_column(self, name: str, type_: str | Type, nullable: Nullable = Nullable.NONE) -> Column:
140141
self.column_index += 1
141142
# noinspection PyArgumentList
142143
return Column(self.column_index, name, type_, nullable)

src/zepben/ewb/database/sqlite/common/base_collection_reader.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def set_identifier(identifier: str) -> str:
7070
count = 0
7171
while results.next():
7272
if process_row(table, results, set_identifier):
73-
count = count + 1
73+
count += 1
7474

7575
return count
7676
except SqlException as e:

src/zepben/ewb/database/sqlite/customer/customer_cim_reader.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from zepben.ewb.model.cim.iec61968.customers.customer_kind import CustomerKind
2323
from zepben.ewb.model.cim.iec61968.customers.pricing_structure import PricingStructure
2424
from zepben.ewb.model.cim.iec61968.customers.tariff import Tariff
25+
from zepben.ewb.model.cim.iec61970.base.domain.date_time_interval import DateTimeInterval
2526
from zepben.ewb.services.customer.customers import CustomerService
2627

2728
class CustomerCimReader(BaseCimReader):
@@ -40,6 +41,12 @@ def __init__(self, service: CustomerService):
4041
###################
4142

4243
def _load_agreement(self, agreement: Agreement, table: TableAgreements, result_set: ResultSet) -> bool:
44+
start = result_set.get_instant(table.validity_interval_start.query_index, on_none=None)
45+
end = result_set.get_instant(table.validity_interval_end.query_index, on_none=None)
46+
47+
if start is not None or end is not None:
48+
agreement.validity_interval = DateTimeInterval(start=start, end=end)
49+
4350
return self._load_document(agreement, table, result_set)
4451

4552
######################

src/zepben/ewb/database/sqlite/customer/customer_cim_writer.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ def __init__(self, database_tables: CustomerDatabaseTables):
3838
###################
3939

4040
def _save_agreement(self, table: TableAgreements, insert: PreparedStatement, agreement: Agreement, description: str) -> bool:
41+
insert.add_value(table.validity_interval_start.query_index, getattr(agreement.validity_interval, 'start', None))
42+
insert.add_value(table.validity_interval_end.query_index, getattr(agreement.validity_interval, 'end', None))
4143
return self._save_document(table, insert, agreement, description)
4244

4345
######################

src/zepben/ewb/database/sqlite/extensions/result_set.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def get_string(self, column_index: int, on_none: Union[Optional[str], Type[Excep
5555
value = self._current_row[column_index - 1]
5656
if value is None:
5757
return self._value_or_raise(on_none)
58-
elif isinstance(value, str):
58+
elif isinstance(value, str) or on_none is None: # FIXME: TESTING HAX!! this shouldnt be in the PR
5959
return value
6060
else:
6161
raise ValueError

0 commit comments

Comments
 (0)