Orange-OpenSource / its-client

This Intelligent Transportation Systems (ITS) MQTT client based on the JSon ETSI specification transcription provides a ready to connect project for the mobility (connected and autonomous vehicles, road side units, vulnerable road users,...). Let's connect your device or application to our Intelligent Transport Systems (ITS) platform!
MIT License
7 stars 8 forks source link

python/iot3: implement mobility SDK #213

Closed ymorin-orange closed 4 days ago

ymorin-orange commented 1 week ago

Features:


Preparation:

  1. if you do not have a gpsd server listening on localhost:2947, spawn one (needs gpsd 3.24 or later):
    • grab the NMEA sample on Wikipedia and save it in a file called NMEA.log
    • start a gpsfake using that file to emulate a GNSS device:
      TMPDIR=/tmp gpsfake -q -P 2947 -o=-G -u -n -c 0.1 NMEA.log
  2. if you do not have python 3.11 or later, you can use the following to create a container to run all the tests:
    • start a container with python 3.11:
      $ docker container run \
          --detach \
          --name iot3 \
          --rm \
          -ti \
          --network host \
          -e http_proxy \
          -e https_proxy \
          -e no_proxy \
          --user $(id -u):$(id -u) \
          --mount type=bind,source=$(pwd),destination=$(pwd) \
          --workdir $(pwd) \
          python:3.11.9-slim-bookworm \
          /bin/bash -il
    • install the necessary packages:
      $ docker container exec -u 0:0 iot3 apt update
      $ docker container exec -u 0:0 iot3 apt install -y git
    • attach to the container:
      $ docker container attach iot3
  3. start an MQTT client to dump messages (in another terminal):
    $ mosquitto_sub -h test.mosquitto.org -p 1883 -V mqttv5 -t "default/inQueue/v2x/#" -F %J |jq -C .

How to test:

  1. Create and activate a virtual-env to run the tests:
    [python-3.11] $ python3.11 -m venv /tmp/iot3
    [python-3.11] $ . /tmp/iot3/bin/activate
  2. Install the IoT3 SDK:
    [python-3.11] $ pip install python/iot3
  3. Run the IoT3 Mobility SDK test-suite:
    [python-3.11] $ ./python/iot3/tests/test-iot3-mobility-gnss
    [python-3.11] $ ./python/iot3/tests/test-iot3-mobility-message
    [python-3.11] $ ./python/iot3/tests/test-iot3-mobility

Expected results:

  1. A python venv is created and activated
  2. The IoT3 SDK is isntalled succesfully
  3. The tests succeed:
    • ./python/iot3/tests/test-iot3-mobility-gnss
      Basic, empty GNSS report...
      Disallow explicit timestamp...
      Validity range...
      Conflicting attributes...
      Attribute degree -> radian conversion...
      Attribute radian -> degree conversion...
      gpsd connection to 127.0.0.1:2947...
    • ./python/iot3/tests/test-iot3-mobility-message
      CAM with nothing available...
      CAM with latitude and longitude...
      CAM serialisation...
      CAM de-serialisation...
      DENM with nothing set...
      DENM with latitude, longitude, and cause...
      DENM continuation (update)...
      DENM continuation (termination)...
      DENM serialisation...
      DENM de-serialisation...
      Invalid generic message...
      De-serialisation of unrecognised message...
      De-serialisation of broken message...
    • ./python/iot3/tests/test-iot3-mobility
      Starting IoT3 Mobility SDK...
      Sending position...
      Sending alert 'accident'...
      Sending alert 'trafficCondition' as if relayed by an IQM...
      alert: (lat 43.635211999999996, lon 1.3745619999999998): trafficCondition

      Note that the accident alert is not reported, while the trafficCondition one is; the MQTT client reports two messages: 1 CAM, and 1 DENM for the accident alert:

      {
        "tst": "2024-11-19T15:36:14.214301Z+0100",
        "topic": "default/inQueue/v2x/cam/1234/1/2/0/2/2/2/0/2/1/3/3/3/1/0/3/0/0/0/3/3/1/2",
        "qos": 0,
        "retain": 0,
        "payloadlen": 520,
        "properties": {
          "user-properties": {
            "traceparent": "00-0acd4c56355b35d4b743d235de2783fe-46ba88bfbc33dda6-00"
          }
        },
        "payload": {
          "type": "cam",
          "origin": "self",
          "version": "1.1.3",
          "source_uuid": "1234",
          "timestamp": 1732026974008,
          "message": {
            "protocol_version": 1,
            "station_id": 240743,
            "generation_delta_time": 34616,
            "basic_container": {
              "station_type": 0,
              "reference_position": {
                "latitude": 436352120,
                "longitude": 13745620,
                "altitude": 800001
              },
              "confidence": {
                "position_confidence_ellipse": {
                  "semi_major_confidence": 4095,
                  "semi_minor_confidence": 4095,
                  "semi_major_orientation": 0
                }
              }
            },
            "high_frequency_container": {
              "heading": 3601,
              "speed": 16383,
              "longitudinal_acceleration": 161
            }
          }
        }
      }
      {
        "tst": "2024-11-19T15:36:15.034743Z+0100",
        "topic": "default/inQueue/v2x/denm/1234/1/2/0/2/2/2/0/2/1/3/3/3/1/0/3/0/0/0/3/3/1/2",
        "qos": 0,
        "retain": 0,
        "payloadlen": 428,
        "properties": {
          "user-properties": {
            "traceparent": "00-09ad8a11a1ac5954f532b8886c5e1c1b-c36f73e3c070d139-00"
          }
        },
        "payload": {
          "type": "denm",
          "origin": "self",
          "version": "1.1.3",
          "source_uuid": "1234",
          "timestamp": 1732026975010,
          "message": {
            "protocol_version": 1,
            "station_id": 240743,
            "management_container": {
              "action_id": {
                "originating_station_id": 240743,
                "sequence_number": 0
              },
              "detection_time": 659111775010,
              "reference_time": 659111775010,
              "event_position": {
                "latitude": 436352120,
                "longitude": 13745620,
                "altitude": 800001
              }
            },
            "situation_container": {
              "event_type": {
                "cause": 2
              }
            }
          }
        }
      }