Beispiel #1
0
    def test_get_sensor(self, mocker: MockFixture) -> None:
        mocker.patch("bacprop.bacnet.network._VLANRouter")
        network = VirtualSensorNetwork("0.0.0.0")

        sensor_created = network.create_sensor(7)
        sensor_found = network.get_sensor(7)

        assert sensor_created == sensor_found
Beispiel #2
0
    def test_create_sensor_exists(self, mocker: MockFixture) -> None:
        mocker.patch("bacprop.bacnet.network._VLANRouter")
        network = VirtualSensorNetwork("0.0.0.0")

        network.create_sensor(7)

        with pytest.raises(ValueError):
            network.create_sensor(7)
Beispiel #3
0
    def test_stop(self, mocker: MockFixture) -> None:
        mock_stop = mocker.patch("bacprop.bacnet.network.stop")

        network = VirtualSensorNetwork("0.0.0.0")
        # Teardown
        network._router.mux.close_socket()
        service_map.clear()

        network.stop()
        mock_stop.assert_called_once()
Beispiel #4
0
    def test_get_sensors(self, mocker: MockFixture) -> None:
        mocker.patch("bacprop.bacnet.network._VLANRouter")
        network = VirtualSensorNetwork("0.0.0.0")

        for i in range(10):
            network.create_sensor(i)

        sensors = network.get_sensors()

        for i in range(10):
            assert type(sensors[i]) == Sensor
Beispiel #5
0
    def test_create_sensor(self, mocker: MockFixture) -> None:
        mocker.patch("bacprop.bacnet.network._VLANRouter")
        network = VirtualSensorNetwork("0.0.0.0")

        sensor = network.create_sensor(7)
        sensor2 = network.create_sensor(8)

        assert len(network.nodes) == 3
        assert network.nodes[-1] == sensor2.get_node()
        assert network.nodes[-2] == sensor.get_node()

        assert sensor._vlan_address == Address((2).to_bytes(4, "big"))
        assert sensor2._vlan_address == Address((3).to_bytes(4, "big"))
Beispiel #6
0
    def test_init_router(self, mocker: MockFixture) -> None:
        mocker.patch("bacprop.bacnet.network._VLANRouter")
        network = VirtualSensorNetwork("0.0.0.0")

        router_node = network.nodes[0]

        # The router node on the network should be address 1
        assert router_node.address == Address((1).to_bytes(4, "big"))

        # pylint: disable=no-member
        network._router.bind.assert_called_once_with(router_node,
                                                     1)  # type: ignore
        network._router.start.assert_called_once()  # type: ignore
Beispiel #7
0
 def __init__(self) -> None:
     BacPropagator._info(f"Intialising SensorStream and Bacnet")
     self._stream = SensorStream()
     self._sensor_net = VirtualSensorNetwork(config.LISTEN)
     self._running = False
Beispiel #8
0
class BacPropagator(Logable):
    # SENSOR_ID_KEY = "deviceName"
    SENSOR_OUTDATED_TIME = 60 * 10  # 10 Minutes

    def __init__(self) -> None:
        BacPropagator._info(f"Intialising SensorStream and Bacnet")
        self._stream = SensorStream()
        self._sensor_net = VirtualSensorNetwork(config.LISTEN)
        self._running = False

        # self._device_id_ = 0

    def _handle_sensor_data(self, data: Dict[str, Any]) -> None:

        if "deviceName" not in data:
            BacPropagator._warning(
                f"Drop for deviceName missing from sensor data: {data}")
            return

        random.seed(data["deviceName"])
        sensor_id = random.randint(0, 1000000)

        if "data" not in data:
            BacPropagator._warning(
                f"Drop for data missing from sensor data: {data}")
            return

        result = data["data"]
        strdata = base64.b64decode(result).hex()
        if len(strdata) < 14:
            BacPropagator._warning(
                f"Drop for data length error from sensor data: {data}")
            return
        temp = strdata[6:8] + strdata[4:6]
        data["temp"] = int(temp, 16) / 10
        data["humidity"] = int(strdata[12:14], 16) / 2
        del data["data"]

        # if BacPropagator.SENSOR_ID_KEY not in data:
        #     BacPropagator._warning(f"sensorId {BacPropagator.SENSOR_ID_KEY} missing from sensor data: {data}")
        #     return

        # try:
        #     sensor_id = int(data[BacPropagator.SENSOR_ID_KEY])
        # except ValueError:
        #     BacPropagator._warning(
        #         f"sensorId {data[BacPropagator.SENSOR_ID_KEY]} could not be decoded"
        #     )
        #     return
        #
        # if len(sensor_id) <= 0:
        #     BacPropagator._warning(
        #         f"sensorId {data[BacPropagator.SENSOR_ID_KEY]} is an invalid id"
        #     )
        #     return
        #
        # del data[BacPropagator.SENSOR_ID_KEY]

        BacPropagator._debug(f"rev {sensor_id} with data: {data}")

        # values: Dict[str, float] = {}
        #
        # # Only allow through data which are actually floats
        # for key in data:
        #     # if type(data[key]) not in (float, int):
        #     #     BacPropagator._warning(
        #     #         f"Recieved non-number value ({key}: '{data[key]}') from sensor id: {sensor_id}"
        #     #     )
        #     # else:
        #     #     values[key] = data[key]
        #     values[key] = data[key]

        sensor = self._sensor_net.get_sensor(sensor_id)

        if not sensor:
            sensor = self._sensor_net.create_sensor(sensor_id)

        sensor.set_values(config.SENSOR_DEFINE["temp"], data)

        if sensor.has_fault():
            if _debug:
                BacPropagator._debug(
                    f"Sensor {sensor_id} now has new data, so marking as OK")
            sensor.mark_ok()

    async def _fault_check_loop(self) -> None:
        BacPropagator._info("Starting fault check loop")
        while self._running:
            for sensor_id, sensor in self._sensor_net.get_sensors().items():
                if (not sensor.has_fault()
                        and abs(time.time() - sensor.get_update_time()) >
                        BacPropagator.SENSOR_OUTDATED_TIME):
                    if _debug:
                        BacPropagator._debug(
                            f"Sensor {sensor_id} data is outdated, notifying fault"
                        )
                    sensor.mark_fault()

            await asyncio.sleep(1)

    async def _main_loop(self) -> None:
        BacPropagator._info("Starting stream receive loop")
        await self._stream.start()

        async for data in self._stream.read():
            if _debug:
                BacPropagator._debug(f"Received: {data}")

            self._handle_sensor_data(data)

    def _start_bacnet_thread(self) -> Thread:
        BacPropagator._info("Starting bacnet sensor network")

        bacnet_thread = Thread(target=self._sensor_net.run)
        bacnet_thread.daemon = True
        bacnet_thread.start()

        return bacnet_thread

    def start(self) -> None:
        self._running = True

        bacnet_thread = self._start_bacnet_thread()

        asyncio.ensure_future(self._fault_check_loop())

        loop = asyncio.get_event_loop()
        try:
            loop.run_until_complete(self._main_loop())
        except KeyboardInterrupt:
            pass
        except:
            traceback.print_exc()

        self._running = False

        BacPropagator._info("Stopping stream loop")
        loop.run_until_complete(self._stream.stop())

        BacPropagator._info("Closing bacnet sensor network")
        self._sensor_net.stop()
        bacnet_thread.join()
Beispiel #9
0
    def test_init_address(self, mocker: MockFixture) -> None:
        mock_router = mocker.patch("bacprop.bacnet.network._VLANRouter")

        VirtualSensorNetwork("0.0.0.0")
        mock_router.assert_called_once_with(Address("0.0.0.0"), 0)