def __post_init__(self): if self.targets is None and self.targets_by_type is None: return elif self.targets_by_type is None: list_of_targets = [asdict(target) if is_dataclass(target) else target for target in self.targets] self.targets_by_type = group_targets_by_type(list_of_targets) elif self.targets is None: self.targets = [Target(**target) for target in ungroup_targets_by_type(self.targets_by_type)] elif self.targets is not None and self.targets_by_type is not None: list_of_targets = [asdict(target) if is_dataclass(target) else target for target in self.targets] if group_targets_by_type(list_of_targets) != self.targets_by_type: raise ValueError("You assigned both 'targets' and 'targets_by_type' in your event, " "but the two were not consistent with each other. " f"You supplied 'targets' = {self.targets} and " f"'targets_by_type' = {self.targets_by_type}")
def __post_init__(self): if self.active_period is None: dtstart = min([ i['dtstart'] if isinstance(i, dict) else i.dtstart for s in self.event_signals for i in s.intervals ]) duration = max([ i['dtstart'] + i['duration'] if isinstance(i, dict) else i.dtstart + i.duration for s in self.event_signals for i in s.intervals ]) - dtstart self.active_period = ActivePeriod(dtstart=dtstart, duration=duration) if self.targets is None and self.targets_by_type is None: raise ValueError( "You must supply either 'targets' or 'targets_by_type'.") elif self.targets_by_type is None: list_of_targets = [ asdict(target) if is_dataclass(target) else target for target in self.targets ] self.targets_by_type = utils.group_targets_by_type(list_of_targets) elif self.targets is None: self.targets = [ Target(**target) for target in utils.ungroup_targets_by_type( self.targets_by_type) ] elif self.targets is not None and self.targets_by_type is not None: list_of_targets = [ asdict(target) if is_dataclass(target) else target for target in self.targets ] if utils.group_targets_by_type( list_of_targets) != self.targets_by_type: raise ValueError( "You assigned both 'targets' and 'targets_by_type' in your event, " "but the two were not consistent with each other. " f"You supplied 'targets' = {self.targets} and " f"'targets_by_type' = {self.targets_by_type}") # Set the event status self.event_descriptor.event_status = utils.determine_event_status( self.active_period)
def __post_init__(self): if self.signal_type not in enums.SIGNAL_TYPE.values: raise ValueError( f"""The signal_type must be one of '{"', '".join(enums.SIGNAL_TYPE.values)}', """ f"""you specified: '{self.signal_type}'.""") if self.signal_name not in enums.SIGNAL_NAME.values and not self.signal_name.startswith( 'x-'): raise ValueError( f"""The signal_name must be one of '{"', '".join(enums.SIGNAL_TYPE.values)}', """ f"""or it must begin with 'x-'. You specified: '{self.signal_name}'""" ) if self.targets is None and self.targets_by_type is None: return elif self.targets_by_type is None: list_of_targets = [ asdict(target) if is_dataclass(target) else target for target in self.targets ] targets_by_type = utils.group_targets_by_type(list_of_targets) if len(targets_by_type) > 1: raise ValueError( "In OpenADR, the EventSignal target may only be of type endDeviceAsset. " f"You provided types: '{', '.join(targets_by_type)}'") elif self.targets is None: self.targets = [ Target(**target) for target in utils.ungroup_targets_by_type( self.targets_by_type) ] elif self.targets is not None and self.targets_by_type is not None: list_of_targets = [ asdict(target) if is_dataclass(target) else target for target in self.targets ] if utils.group_targets_by_type( list_of_targets) != self.targets_by_type: raise ValueError( "You assigned both 'targets' and 'targets_by_type' in your event, " "but the two were not consistent with each other. " f"You supplied 'targets' = {self.targets} and " f"'targets_by_type' = {self.targets_by_type}")
def create_dummy_event(ven_id): """ Creates a dummy event """ now = datetime.now(timezone.utc) event_id = generate_id() active_period = {"dtstart": (now + timedelta(minutes=1)), "duration": timedelta(minutes=9)} event_descriptor = {"event_id": event_id, "modification_number": 1, "modification_date_time": now, "priority": 1, "market_context": "http://MarketContext1", "created_date_time": now, "event_status": "near", "test_event": False, "vtn_comment": "This is an event"} event_signals = [{"intervals": [{"duration": timedelta(minutes=1), "uid": 0, "signal_payload": 8.0}, {"duration": timedelta(minutes=1), "uid": 1, "signal_payload": 10.0}, {"duration": timedelta(minutes=1), "uid": 2, "signal_payload": 12.0}, {"duration": timedelta(minutes=1), "uid": 3, "signal_payload": 14.0}, {"duration": timedelta(minutes=1), "uid": 4, "signal_payload": 16.0}, {"duration": timedelta(minutes=1), "uid": 5, "signal_payload": 18.0}, {"duration": timedelta(minutes=1), "uid": 6, "signal_payload": 20.0}, {"duration": timedelta(minutes=1), "uid": 7, "signal_payload": 10.0}, {"duration": timedelta(minutes=1), "uid": 8, "signal_payload": 20.0}], "signal_name": "LOAD_CONTROL", "signal_type": "x-loadControlCapacity", "signal_id": generate_id(), "measurement": {"name": "voltage", "description": "Voltage", "unit": "V", "scale": "none"}, "current_value": 0.0}] event_targets = [{"ven_id": 'VEN001'}, {"ven_id": 'VEN002'}] event = {'active_period': active_period, 'event_descriptor': event_descriptor, 'event_signals': event_signals, 'targets': event_targets, 'targets_by_type': group_targets_by_type(event_targets), 'response_required': 'always'} return event
def _preflight_oadrDistributeEvent(message_payload): if 'parse_duration' not in globals(): from .utils import parse_duration # Check that the total event_duration matches the sum of the interval durations (rule 8) for event in message_payload['events']: active_period_duration = event['active_period']['duration'] signal_durations = [] for signal in event['event_signals']: signal_durations.append( sum([ parse_duration(i['duration']) for i in signal['intervals'] ], timedelta(seconds=0))) if not all([d == active_period_duration for d in signal_durations]): if not all([d == signal_durations[0] for d in signal_durations]): raise ValueError( "The different EventSignals have different total durations. " "Please correct this.") else: logger.warning( f"The active_period duration for event " f"{event['event_descriptor']['event_id']} ({active_period_duration})" f" differs from the sum of the interval's durations " f"({signal_durations[0]}). The active_period duration has been " f"adjusted to ({signal_durations[0]}).") event['active_period']['duration'] = signal_durations[0] # Check that payload values with signal name SIMPLE are constricted (rule 9) for event in message_payload['events']: for event_signal in event['event_signals']: if event_signal['signal_name'] == "SIMPLE": for interval in event_signal['intervals']: if interval['signal_payload'] not in (0, 1, 2, 3): raise ValueError( "Payload Values used with Signal Name SIMPLE " "must be one of 0, 1, 2 or 3") # Check that the current_value is 0 for SIMPLE events that are not yet active (rule 14) for event in message_payload['events']: for event_signal in event['event_signals']: if 'current_value' in event_signal and event_signal[ 'current_value'] != 0: if event_signal['signal_name'] == "SIMPLE" \ and event['event_descriptor']['event_status'] != "ACTIVE": logger.warning("The current_value for a SIMPLE event " "that is not yet active must be 0. " "This will be corrected.") event_signal['current_value'] = 0 # Check that there is a valid oadrResponseRequired value for each Event for event in message_payload['events']: if 'response_required' not in event: event['response_required'] = 'always' elif event['response_required'] not in ('never', 'always'): logger.warning( f"The response_required property in an Event " f"should be 'never' or 'always', not " f"{event['response_required']}. Changing to 'always'.") event['response_required'] = 'always' # Check that there is a valid oadrResponseRequired value for each Event for event in message_payload['events']: if 'created_date_time' not in event['event_descriptor'] \ or not event['event_descriptor']['created_date_time']: event['event_descriptor']['created_date_time'] = datetime.now( timezone.utc) # Check that the target designations are correct and consistent for event in message_payload['events']: if 'targets' in event and 'targets_by_type' in event: if utils.group_targets_by_type( event['targets']) != event['targets_by_type']: raise ValueError( "You assigned both 'targets' and 'targets_by_type' in your event, " "but the two were not consistent with each other. " f"You supplied 'targets' = {event['targets']} and " f"'targets_by_type' = {event['targets_by_type']}") elif 'targets_by_type' in event and 'targets' not in event: event['targets'] = utils.ungroup_targets_by_type( event['targets_by_type'])
('oadrCreatedPartyRegistration', dict(response={'response_code': 200, 'response_description': 'OK', 'request_id': generate_id()}, registration_id=generate_id(), ven_id='123ABC', profiles=[{'profile_name': '2.0b', 'transports': [{'transport_name': 'simpleHttp'}]}], vtn_id='VTN123')), ('oadrCreatedReport', dict(response={'response_code': 200, 'response_description': 'OK', 'request_id': generate_id()}, pending_reports=[{'request_id': generate_id()}, {'request_id': generate_id()}])), ('oadrCreateOpt', dict(opt_id=generate_id(), opt_type='optIn', opt_reason='participating', created_date_time=datetime.now(timezone.utc), request_id=generate_id(), event_id=generate_id(), modification_number=1, targets=[{'ven_id': '123ABC'}], targets_by_type=group_targets_by_type([{'ven_id': '123ABC'}]), ven_id='VEN123')), ('oadrCreatePartyRegistration', dict(request_id=generate_id(), ven_id='123ABC', profile_name='2.0b', transport_name='simpleHttp', transport_address='http://localhost', report_only=False, xml_signature=False, ven_name='test', http_pull_model=True)), ('oadrCreateReport', dict(request_id=generate_id(), ven_id='123ABC', report_requests=[{'report_request_id': 'd2b7bade5f', 'report_specifier': {'granularity': timedelta(seconds=900), 'report_back_duration': timedelta(seconds=900), 'report_interval': {'dtstart': datetime(2019, 11, 19, 11, 0, 18, 672768, tzinfo=timezone.utc), 'duration': timedelta(seconds=7200)}, 'report_specifier_id': '9c8bdc00e7', 'specifier_payloads': [{'r_id': 'd6e2e07485', 'reading_type': 'Direct Read'}]}}])), ('oadrDistributeEvent', dict(request_id=generate_id(), response={'request_id': 123, 'response_code': 200, 'response_description': 'OK'}, events=[create_dummy_event(ven_id='123ABC')], vtn_id='VTN123')), ('oadrDistributeEvent', dict(request_id=generate_id(), response={'request_id': 123, 'response_code': 200, 'response_description': 'OK'}, events=[create_dummy_event(ven_id='123ABC'), create_dummy_event(ven_id='123ABC')], vtn_id='VTN123')), ('oadrPoll', dict(ven_id='123ABC')),