Skip to content

Commit

Permalink
roll up changes and release 0.18.4
Browse files Browse the repository at this point in the history
  • Loading branch information
Joel Bender committed Mar 24, 2021
2 parents 825e016 + ddc6a1b commit 9fca3f6
Show file tree
Hide file tree
Showing 37 changed files with 3,517 additions and 319 deletions.
104 changes: 104 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions

name: Build & test on different versions

on:
push:
branches: [ master, develop ]
pull_request:
branches: [ master, develop ]

jobs:
build:
name: Linux - Install and test
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.6, 3.7, 3.8]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8 pytest
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
pip install .
# - name: Lint with flake8
# run: |
# # stop the build if there are Python syntax errors or undefined names
# flake8 py34 --count --select=E9,F63,F7,F82 --show-source --statistics --ignore=E123,E221,E226,E302,E41,E701
# # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
# flake8 py34 --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics --ignore=E123,E221,E226,E302,E41,E701
- name: Test with pytest
run: |
pytest -v
legacy-build:
name: Legacy versions - Install and test
runs-on: ubuntu-18.04
strategy:
matrix:
python-version: [2.7, 3.4, 3.5]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
pip install pytest
pip install setuptools --upgrade
python setup.py install
- name: Test with pytest
run: |
pytest -v
windows-build:
name: Windows - Install and test
runs-on: windows-latest
strategy:
matrix:
python-version: [3.6, 3.7, 3.8]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8 pytest
pip install -r requirements.txt
pip install .
- name: Test with pytest
run: |
pytest -v
macos-build:
name: MacOS - Install and test
runs-on: macos-latest
strategy:
matrix:
python-version: [3.6, 3.7, 3.8]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8 pytest
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
pip install .
- name: Test with pytest
run: |
pytest -v
2 changes: 1 addition & 1 deletion py25/bacpypes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
# Project Metadata
#

__version__ = '0.18.3'
__version__ = '0.18.4'
__author__ = 'Joel Bender'
__email__ = '[email protected]'

Expand Down
57 changes: 49 additions & 8 deletions py25/bacpypes/bvllservice.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from .debugging import ModuleLogger, DebugContents, bacpypes_debugging

from .udp import UDPDirector
from .task import OneShotTask, RecurringTask
from .task import OneShotFunction, OneShotTask, RecurringTask
from .comm import Client, Server, bind, \
ServiceAccessPoint, ApplicationServiceElement

Expand Down Expand Up @@ -483,6 +483,9 @@ def __init__(self, addr=None, ttl=None, sapID=None, cid=None, sid=None):
self.bbmdAddress = None
self.bbmdTimeToLive = None

# used in tracking active registration timeouts
self._registration_timeout_task = OneShotFunction(self._registration_expired)

# registration provided
if addr:
# a little error checking
Expand Down Expand Up @@ -539,10 +542,9 @@ def confirmation(self, pdu):
# save the result code as the status
self.registrationStatus = pdu.bvlciResultCode

# check for success
if pdu.bvlciResultCode == 0:
# schedule for a refresh
self.install_task(delta=self.bbmdTimeToLive)
# If successful, track registration timeout
if self.registrationStatus == 0:
self._start_track_registration()

return

Expand Down Expand Up @@ -633,7 +635,11 @@ def confirmation(self, pdu):
BIPForeign._warning("invalid pdu type: %s", type(pdu))

def register(self, addr, ttl):
"""Initiate the process of registering with a BBMD."""
"""Start the foreign device registration process with the given BBMD.
Registration will be renewed periodically according to the ttl value
until explicitly stopped by a call to `unregister`.
"""
# a little error checking
if ttl <= 0:
raise ValueError("time-to-live must be greater than zero")
Expand All @@ -645,11 +651,18 @@ def register(self, addr, ttl):
self.bbmdAddress = Address(addr)
self.bbmdTimeToLive = ttl

# install this task to run when it gets a chance
# install this task to do registration renewal according to the TTL
# and stop tracking any active registration timeouts
self.install_task(when=0)
self._stop_track_registration()

def unregister(self):
"""Drop the registration with a BBMD."""
"""Stop the foreign device registration process.
Immediately drops active foreign device registration and stops further
registration renewals.
"""

pdu = RegisterForeignDevice(0)
pdu.pduDestination = self.bbmdAddress

Expand All @@ -663,6 +676,11 @@ def unregister(self):
self.bbmdAddress = None
self.bbmdTimeToLive = None

# unschedule registration renewal & timeout tracking if previously
# scheduled
self.suspend_task()
self._stop_track_registration()

def process_task(self):
"""Called when the registration request should be sent to the BBMD."""
pdu = RegisterForeignDevice(self.bbmdTimeToLive)
Expand All @@ -671,6 +689,29 @@ def process_task(self):
# send it downstream
self.request(pdu)

# schedule the next registration renewal
self.install_task(delta=self.bbmdTimeToLive)

def _start_track_registration(self):
# From J.5.2.3 Foreign Device Table Operation (paraphrasing): if a
# foreign device does not renew its registration 30 seconds after its
# TTL expired then it will be removed from the BBMD's FDT.
#
# Thus, if we're registered and don't get a response to a subsequent
# renewal request 30 seconds after our TTL expired then we're
# definitely not registered anymore.
self._registration_timeout_task.install_task(delta=self.bbmdTimeToLive + 30)

def _stop_track_registration(self):
self._registration_timeout_task.suspend_task()

def _registration_expired(self):
"""Called when detecting that foreign device registration has
definitely expired.
"""
self.registrationStatus = -1 # Unregistered
self._stop_track_registration()

bacpypes_debugging(BIPForeign)

#
Expand Down
4 changes: 2 additions & 2 deletions py25/bacpypes/local/object.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ class CurrentPropertyListMixIn(Object):
# character reference patterns
HEX = u"[0-9A-Fa-f]"
PERCENT = u"%" + HEX + HEX
UCHAR = u"[\\\]u" + HEX * 4 + "|" + u"[\\\]U" + HEX * 8
UCHAR = u"[\\]u" + HEX * 4 + "|" + u"[\\]U" + HEX * 8

# character sets
PN_CHARS_BASE = (
Expand All @@ -102,7 +102,7 @@ class CurrentPropertyListMixIn(Object):
PN_CHARS = u"-" + PN_CHARS_U + u"0-9\u00B7\u0300-\u036F\u203F-\u2040"

# patterns
IRIREF = u'[<]([^\u0000-\u0020<>"{}|^`\\\]|' + UCHAR + u")*[>]"
IRIREF = u'[<]([^\u0000-\u0020<>"{}|^`\\]|' + UCHAR + u")*[>]"
PN_PREFIX = u"[" + PN_CHARS_BASE + u"](([." + PN_CHARS + u"])*[" + PN_CHARS + u"])?"

PN_LOCAL_ESC = u"[-\\_~.!$&'()*+,;=/?#@%]"
Expand Down
12 changes: 10 additions & 2 deletions py25/bacpypes/primitivedata.py
Original file line number Diff line number Diff line change
Expand Up @@ -1612,7 +1612,8 @@ def __str__(self):
class ObjectType(Enumerated):
vendor_range = (128, 1023)
enumerations = \
{ 'accessDoor':30
{ 'accessCredential':32
, 'accessDoor':30
, 'accessPoint':33
, 'accessRights':34
, 'accessUser':35
Expand All @@ -1622,8 +1623,11 @@ class ObjectType(Enumerated):
, 'analogInput':0
, 'analogOutput':1
, 'analogValue':2
, 'auditLog':61
, 'auditReporter':62
, 'averaging':18
, 'binaryInput':3
, 'binaryLightingOutput':55
, 'binaryOutput':4
, 'binaryValue':5
, 'bitstringValue':39
Expand All @@ -1637,6 +1641,8 @@ class ObjectType(Enumerated):
, 'datetimePatternValue':43
, 'datetimeValue':44
, 'device':8
, 'elevatorGroup':57
, 'escalator':58
, 'eventEnrollment':9
, 'eventLog':25
, 'file':10
Expand All @@ -1646,13 +1652,15 @@ class ObjectType(Enumerated):
, 'largeAnalogValue':46
, 'lifeSafetyPoint':21
, 'lifeSafetyZone':22
, 'lift':59
, 'lightingOutput':54
, 'loadControl':28
, 'loop':12
, 'multiStateInput':13
, 'multiStateOutput':14
, 'multiStateValue':19
, 'networkSecurity':38
, 'networkPort':56
, 'notificationClass':15
, 'notificationForwarder':51
, 'octetstringValue':47
Expand All @@ -1663,9 +1671,9 @@ class ObjectType(Enumerated):
, 'structuredView':29
, 'timePatternValue':49
, 'timeValue':50
, 'timer':31
, 'trendLog':20
, 'trendLogMultiple':27
, 'networkPort':56
}

expand_enumerations(ObjectType)
Expand Down
8 changes: 4 additions & 4 deletions py25/bacpypes/service/cov.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class Subscription(OneShotTask, DebugContents):
'lifetime',
)

def __init__(self, obj_ref, client_addr, proc_id, obj_id, confirmed, lifetime):
def __init__(self, obj_ref, client_addr, proc_id, obj_id, confirmed, lifetime=0):
if _debug: Subscription._debug("__init__ %r %r %r %r %r %r", obj_ref, client_addr, proc_id, obj_id, confirmed, lifetime)
OneShotTask.__init__(self)

Expand All @@ -103,9 +103,9 @@ def __init__(self, obj_ref, client_addr, proc_id, obj_id, confirmed, lifetime):
self.confirmed = confirmed
self.lifetime = lifetime

# if lifetime is non-zero, schedule the subscription to expire
if lifetime != 0:
self.install_task(delta=self.lifetime)
# if lifetime is none, consider permanent subscription (0)
self.lifetime = 0 if lifetime is None else lifetime
self.install_task(delta=self.lifetime)

def cancel_subscription(self):
if _debug: Subscription._debug("cancel_subscription")
Expand Down
2 changes: 1 addition & 1 deletion py27/bacpypes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
# Project Metadata
#

__version__ = '0.18.3'
__version__ = '0.18.4'
__author__ = 'Joel Bender'
__email__ = '[email protected]'

Expand Down
Loading

0 comments on commit 9fca3f6

Please sign in to comment.