#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 by Christian Tremblay, P.Eng <christian.tremblay@servisys.com>
# Licensed under LGPLv3, see file LICENSE in this source tree.
#
# --- standard Python modules ---
import datetime
import typing as t
from bacpypes3.apdu import WritePropertyRequest
from bacpypes3.app import Application
from bacpypes3.basetypes import CalendarEntry, DateRange
from bacpypes3.constructeddata import Any, ArrayOf
# --- 3rd party modules ---
from bacpypes3.pdu import Address
from ...core.app.asyncApp import BAC0Application
from ...core.utils.notes import note_and_log
[docs]
@note_and_log
class Calendar:
"""
Everything you need to write dates and date ranges to a calendar object.
"""
DateList = ArrayOf(CalendarEntry)
datelist_example = {
"dates": [
{"date": "2021/3/14", "recurring": False},
{"date": "2021/3/10", "recurring": True},
],
"dateRanges": [
{"startDate": "2021/3/16", "endDate": "2021/3/21"},
{"startDate": "2021/3/5", "endDate": "2021/3/7"},
],
}
[docs]
def create_calendar(self, dict_calendar):
"""
From a structured dict (see dateList_example), create a DateList
an ArrayOf(CalendarEntry)
"""
entries = []
if "dates" in dict_calendar.keys():
for date_entry in dict_calendar["dates"]:
year, month, day = (int(x) for x in date_entry["date"].split("/"))
if date_entry["recurring"]:
weekday = 255
else:
weekday = datetime.date(year, month, day).weekday() + 1
if weekday > 7:
weekday = 1
_date = (year - 1900, month, day, weekday)
entries.append(CalendarEntry(date=_date))
if "dateRanges" in dict_calendar.keys():
for date_range_entry in dict_calendar["dateRanges"]:
year, month, day = (
int(x) for x in date_range_entry["startDate"].split("/")
)
weekday = datetime.date(year, month, day).weekday() + 1
if weekday > 7:
weekday = 1
start_date = (year - 1900, month, day, weekday)
year, month, day = (
int(x) for x in date_range_entry["endDate"].split("/")
)
weekday = datetime.date(year, month, day).weekday() + 1
if weekday > 7:
weekday = 1
end_date = (year - 1900, month, day, weekday)
date_range = DateRange(startDate=start_date, endDate=end_date)
entries.append(CalendarEntry(dateRange=date_range))
dateList = self.DateList(entries)
return dateList
[docs]
def make_calendar_request(self, destination, object_instance, dateList):
request = WritePropertyRequest(
objectIdentifier=("calendar", object_instance),
propertyIdentifier="dateList",
)
address = Address(destination)
request.pduDestination = address
request.propertyValue = Any(None)
request.propertyValue.cast_in(dateList)
return request
[docs]
def send_calendar_request(self, request, timeout=10):
_this_application: BAC0Application = self.this_application
_app: Application = _this_application.app
self.log(f"{'- request:':>12} {request}", level="debug")
_app.request(request)
self._log.info(
f"Calendar Write request sent to device : {request.pduDestination}"
)
[docs]
def write_calendar_dateList(self, destination, calendar_instance, dates):
calendar = self.create_calendar(dates)
request = self.make_calendar_request(
destination=destination,
object_instance=calendar_instance,
dateList=calendar,
)
self.send_calendar_request(request)
[docs]
async def read_calendar_dateList(self, address, calendar_instance):
"""
This function will read the dateList property of given calendar object and
pass it to decode_dateList() to convert it into a human readable dict.
"""
try:
dateList_object = await self.read(
f"{address} calendar {calendar_instance} dateList"
)
dict_calendar = self.decode_dateList(dateList_object)
except Exception as error:
self.log(f"exception: {error!r}", level="error")
return {}
return dict_calendar
[docs]
def decode_dateList(self, dateList_object) -> t.Dict[str, t.List[t.Dict]]:
dict_calendar = {"dates": [], "dateRanges": []}
for entry in dateList_object:
entry_dict: t.Dict[str, t.Union[str, bool]] = {}
if entry.date:
if entry.date[3] == 255:
recurring = True
else:
recurring = False
entry_dict["date"] = "{}/{}/{}".format(
entry.date[0] + 1900, entry.date[1], entry.date[2]
)
entry_dict["recurring"] = recurring
dict_calendar["dates"].append(entry_dict)
elif entry.dateRange:
entry_dict["startDate"] = "{}/{}/{}".format(
entry.dateRange.startDate[0] + 1900,
entry.dateRange.startDate[1],
entry.dateRange.startDate[2],
)
entry_dict["endDate"] = "{}/{}/{}".format(
entry.dateRange.endDate[0] + 1900,
entry.dateRange.endDate[1],
entry.dateRange.endDate[2],
)
dict_calendar["dateRanges"].append(entry_dict)
return dict_calendar