Skip to content

Commit

Permalink
[DEV-1744] Data model change for HCM intervention (#194)
Browse files Browse the repository at this point in the history
Signed-off-by: Jimmy Tung <[email protected]>
Co-authored-by: Marcus Koh <[email protected]>
Co-authored-by: kgreav <[email protected]>
Co-authored-by: Anthony Charlton <[email protected]>
  • Loading branch information
4 people authored Dec 19, 2024
1 parent 972001f commit ffdf10a
Show file tree
Hide file tree
Showing 77 changed files with 3,617 additions and 127 deletions.
7 changes: 4 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,10 @@ Our main style requirements are:

NOTE: Do not update the StupidlyLargeNetwork file, this will be phased out.

1. *ServiceComparator(s) updated and tested.
2. Exhaustive when functions in *ServiceUtils updated if a new class is added. Update *ServiceUtilsTest to match.
3. Release notes updated.
1. *ServiceComparator(s) updated.
2. *ServiceComparatorTest(s) added for each new class and property.
3. Exhaustive when functions in *ServiceUtils updated if a new class is added. Update *ServiceUtilsTest to match.
4. Release notes updated.

## Adding support for new services ##

Expand Down
18 changes: 16 additions & 2 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
## [0.24.0] - UNRELEASED
### Breaking Changes
* Database readers and writes for each `BaseService` no longer accept a `MetadataCollection`, and will instead use the collection of the provided service.
* `AcLineSegment.perLengthSequenceImpedance` has been corrected to `perLengthImpedance`. This has been done in a non-breaking way, however the public resolver
`Resolvers.perLengthSequenceImpedance` is now `Resolvers.perLengthImpedance`, correctly reflecting the CIM relationship.

### New Features
* Network state services for updating and querying network state events via gRPC.
Expand All @@ -10,12 +12,24 @@
* Added `Services`, a new class which contains a copy of each `BaseService` supported by the SDK.
* Added `connectWithAccessTokenInsecure()` for connecting to a gRPC service using an access token without SSL/TLS.
* Added `connectWithAccessToken()` for connecting to a gRPC service using an access token with SSL/TLS.
* Added `PanDemandResponseFunction`, a new class which contains `EndDeviceFunctionKind` and the identity of the `ControlledAppliance` of this function.
* Added `BatteryControl`, a new class which describes behaviour specific to controlling a `BatteryUnit`.
* Added `StaticVarCompensator` a new class representing a facility for providing variable and controllable shunt reactive power.
* Added `ControlledAppliance` a new class representing the identity of the appliance controlled by a specific `EndDeviceFunction`.
* Added `PerLengthPhaseImpedance` a new class used for representing the impedance of individual wires on an AcLineSegment.
* Added `PhaseImpedanceData` a data class with a link to `PerLengthPhaseImpedance`, for capturing the phase impedance data of an individual wire.
* Added new enums:
* `BatteryControlMode`
* `EndDeviceFunctionKind`
* `SVCControlMode`

### Enhancements
* None.
* Added `ctPrimary` and `minTargetDeadband` to `RegulatingContrl`.
* Added collection of `BatteryControl` to `BatteryUnit`
* Added collection of `EndDeviceFunctionKind` to `EndDevice`
* Added an unordered collection comparator.

### Fixes
* None.

### Notes
* None.
Expand Down
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>com.zepben.maven</groupId>
<artifactId>evolve-super-pom</artifactId>
<version>0.36.4</version>
<version>0.36.7</version>
</parent>

<groupId>com.zepben</groupId>
Expand Down Expand Up @@ -74,7 +74,7 @@
<dependency>
<groupId>com.zepben.protobuf</groupId>
<artifactId>evolve-grpc</artifactId>
<version>0.33.0-SNAPSHOT2</version>
<version>0.33.0-SNAPSHOT4</version>
</dependency>

<dependency>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Copyright 2024 Zeppelin Bend Pty Ltd
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

package com.zepben.evolve.cim.extensions.iec61968.metering

import com.zepben.evolve.cim.extensions.ZBEX
import com.zepben.evolve.cim.iec61968.metering.ControlledAppliance
import com.zepben.evolve.cim.iec61968.metering.EndDeviceFunction
import com.zepben.evolve.cim.iec61968.metering.EndDeviceFunctionKind

/**
* [ZBEX]
* PAN function that an end device supports, distinguished by 'kind'.
*
* @property kind [ZBEX] Kind of this function.
* @property appliance [ZBEX] The appliances being controlled.
*/
@ZBEX
class PanDemandResponseFunction @JvmOverloads constructor(mRID: String = "") : EndDeviceFunction(mRID) {

@ZBEX
var kind: EndDeviceFunctionKind = EndDeviceFunctionKind.UNKNOWN

@ZBEX
var appliance: ControlledAppliance?
get() = applianceBitmask?.let { ControlledAppliance(it) }
set(ca) {
applianceBitmask = ca?.bitmask
}

/**
* The bitmask representation of the appliances being controlled.
*/
internal var applianceBitmask: Int? = null

/**
* Add an appliance to the appliances being controlled.
*
* @param appliance The appliance to add.
* @return True if the controlled appliances were updated.
*/
fun addAppliance(appliance: ControlledAppliance.Appliance): Boolean {
val previous = applianceBitmask

applianceBitmask = (applianceBitmask ?: 0) or appliance.bitmask

return applianceBitmask != previous
}

/**
* Add appliances to the appliances being controlled.
*
* @param appliances The appliances to add.
* @return True if the controlled appliances were updated.
*/
fun addAppliances(vararg appliances: ControlledAppliance.Appliance): Boolean {
require(appliances.isNotEmpty()) { "You must provide at least one appliance to add" }
val previous = applianceBitmask

applianceBitmask = appliances.fold(applianceBitmask ?: 0) { bitmask, next -> bitmask or next.bitmask }

return applianceBitmask != previous
}

/**
* Remove an appliance from the appliances being controlled.
*
* @param appliance The appliance to remove.
* @return True if the controlled appliances were updated.
*/
fun removeAppliance(appliance: ControlledAppliance.Appliance): Boolean {
val previous = applianceBitmask

applianceBitmask = (applianceBitmask ?: 0) and appliance.bitmask.inv()

return applianceBitmask != previous
}

/**
* Remove appliances from the appliances being controlled.
*
* @param appliances Additional appliances to remove.
* @return True if the controlled appliances were updated.
*/
fun removeAppliances(vararg appliances: ControlledAppliance.Appliance): Boolean {
require(appliances.isNotEmpty()) { "You must provide at least one appliance to remove" }
val previous = applianceBitmask

applianceBitmask = (applianceBitmask ?: 0) and appliances.fold(0) { bitmask, next -> bitmask or next.bitmask }.inv()

return applianceBitmask != previous
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright 2024 Zeppelin Bend Pty Ltd
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

package com.zepben.evolve.cim.extensions.iec61970.base.wires

import com.zepben.evolve.cim.extensions.ZBEX
import com.zepben.evolve.cim.iec61970.base.wires.RegulatingControl

/**
* Describes behaviour specific to controlling batteries.
*
* @property chargingRate [ZBEX] Charging rate (input power) in percentage of maxP. (Unit: PerCent)
* @property dischargingRate [ZBEX] Discharge rate (output power) in percentage of maxP. (Unit: PerCent)
* @property reservePercent [ZBEX] Percentage of the rated storage capacity that should be reserved during normal operations. This reserve acts as a safeguard, preventing the energy level
* @property controlMode [ZBEX] Mode of operation for the dispatch (charging/discharging) function of BatteryControl.
*/
@ZBEX
class BatteryControl @JvmOverloads constructor(mRID: String = "") : RegulatingControl(mRID) {

@ZBEX
var chargingRate: Double? = null

@ZBEX
var dischargingRate: Double? = null

@ZBEX
var reservePercent: Double? = null

@ZBEX
var controlMode: BatteryControlMode = BatteryControlMode.UNKNOWN

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Copyright 2024 Zeppelin Bend Pty Ltd
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

package com.zepben.evolve.cim.extensions.iec61970.base.wires

import com.zepben.evolve.cim.extensions.ZBEX

/**
* [ZBEX] Mode of operation for the dispatch (charging/discharging) function of BatteryControl.
*/
@ZBEX
@Suppress("EnumEntryName")
enum class BatteryControlMode {

/**
* Unknown control mode.
*/
@ZBEX
UNKNOWN,

/**
* [ZBEX] This mode directs the BatteryUnit to discharge as needed to maintain the power level of the monitored element within a defined range
* (specified by targetDeadband) or to keep it at or below the value specified by maxAllowedTargetValue. This mode helps prevent power spikes by discharging
* the BatteryUnit to manage peak demand effectively.
*/
@ZBEX
peakShaveDischarge,

/**
* [ZBEX] This mode directs the BatteryUnit to discharge as needed to maintain the current (in amps) at a monitored element below a specified target. Similar
* to peakShaveDischarge, this mode aims to reduce demand peaks, focusing specifically on current levels to manage capacity and enhance system stability where
* current control is essential.
*/
@ZBEX
currentPeakShaveDischarge,

/**
* [ZBEX] The control is triggered by time and resets the targetValue property to the present monitored element power.
*/
@ZBEX
following,

/**
* [ZBEX] This is essentially the opposite of peakShave modes. The fleet is dispatched to keep the power in the monitored terminal at or above targetValue.
*/
@ZBEX
support,

/**
* [ZBEX] In Schedule mode, a trapezoidal-shaped discharge schedule is specified through Tup (up ramp duration), TFlat (at duration),
* and Tdn (down ramp duration) properties.
*/
@ZBEX
schedule,

/**
* [ZBEX] This mode directs the BatteryUnit to initiate charging when the power level at a monitored element falls below a specified threshold (minAllowedTargetValue).
* This mode supports demand leveling by charging the BatteryUnit during low-demand periods, optimizing overall power management.
*/
@ZBEX
peakShaveCharge,

/**
* [ZBEX] This mode initiates charging when the current (in Amps) at a monitored element falls below a specified threshold (minAllowedTargetValue).
* Similar to peakShaveCharge, this mode aims to manage demand effectively, but it operates based on current levels rather than power, providing finer
* control in systems where current management is prioritized.
*/
@ZBEX
currentPeakShaveCharge,

/**
* [ZBEX] In Time mode all storage elements are set to discharge when in the course of simulation the time of day passes the specified hour of day by the
* TimeDisChargeTrigger property (hour is a decimal value, e.g., 10.5 = 1030)
*/
@ZBEX
time,

/**
* [ZBEX] In this mode both discharging and charging precisely follow a per-unit curve.
*/
@ZBEX
profile,

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Copyright 2024 Zeppelin Bend Pty Ltd
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

package com.zepben.evolve.cim.iec61968.assets

import com.zepben.evolve.cim.iec61970.base.core.IdentifiedObject

/**
* Function performed by an asset.
*/
abstract class AssetFunction(mRID: String = "") : IdentifiedObject(mRID)
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright 2024 Zeppelin Bend Pty Ltd
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

package com.zepben.evolve.cim.iec61968.metering

/**
* Appliance controlled with a PAN device control.
*
* @property isElectricVehicle True if the appliance is an electric vehicle.
* @property isExteriorLighting True if the appliance is exterior lighting.
* @property isGenerationSystem True if the appliance is a generation system.
* @property isHvacCompressorOrFurnace True if the appliance is HVAC compressor or furnace.
* @property isInteriorLighting True if the appliance is interior lighting.
* @property isIrrigationPump True if the appliance is an irrigation pump.
* @property isManagedCommercialIndustrialLoad True if the appliance is managed commercial or industrial load.
* @property isPoolPumpSpaJacuzzi True if the appliance is a pool, pump, spa or jacuzzi.
* @property isSimpleMiscLoad True if the appliance is a simple miscellaneous load.
* @property isSmartAppliance True if the appliance is a smart appliance.
* @property isStripAndBaseboardHeater True if the appliance is a strip or baseboard heater.
* @property isWaterHeater True if the appliance is a water heater.
*/
data class ControlledAppliance(internal val bitmask: Int) {

constructor(appliance: Appliance) : this(appliance.bitmask)
constructor(appliance: Appliance, vararg appliances: Appliance) : this(appliances.fold(appliance.bitmask) { bitmask, next -> bitmask or next.bitmask })

val isElectricVehicle: Boolean get() = Appliance.ELECTRIC_VEHICLE in bitmask
val isExteriorLighting: Boolean get() = Appliance.EXTERIOR_LIGHTING in bitmask
val isGenerationSystem: Boolean get() = Appliance.GENERATION_SYSTEM in bitmask
val isHvacCompressorOrFurnace: Boolean get() = Appliance.HVAC_COMPRESSOR_OR_FURNACE in bitmask
val isInteriorLighting: Boolean get() = Appliance.INTERIOR_LIGHTING in bitmask
val isIrrigationPump: Boolean get() = Appliance.IRRIGATION_PUMP in bitmask
val isManagedCommercialIndustrialLoad: Boolean get() = Appliance.MANAGED_COMMERCIAL_INDUSTRIAL_LOAD in bitmask
val isPoolPumpSpaJacuzzi: Boolean get() = Appliance.POOL_PUMP_SPA_JACUZZI in bitmask
val isSimpleMiscLoad: Boolean get() = Appliance.SIMPLE_MISC_LOAD in bitmask
val isSmartAppliance: Boolean get() = Appliance.SMART_APPLIANCE in bitmask
val isStripAndBaseboardHeater: Boolean get() = Appliance.STRIP_AND_BASEBOARD_HEATER in bitmask
val isWaterHeater: Boolean get() = Appliance.WATER_HEATER in bitmask

enum class Appliance(index: Int) {
ELECTRIC_VEHICLE(0),
EXTERIOR_LIGHTING(1),
GENERATION_SYSTEM(2),
HVAC_COMPRESSOR_OR_FURNACE(3),
INTERIOR_LIGHTING(4),
IRRIGATION_PUMP(5),
MANAGED_COMMERCIAL_INDUSTRIAL_LOAD(6),
POOL_PUMP_SPA_JACUZZI(7),
SIMPLE_MISC_LOAD(8),
SMART_APPLIANCE(9),
STRIP_AND_BASEBOARD_HEATER(10),
WATER_HEATER(11);

val bitmask: Int = 1 shl index
}

private operator fun Int.contains(appliance: Appliance): Boolean = (this and appliance.bitmask) != 0

}
Loading

0 comments on commit ffdf10a

Please sign in to comment.