Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

python: migrate applications to use IoT3 Core SDK #149

Draft
wants to merge 18 commits into
base: master
Choose a base branch
from

Conversation

ymorin-orange
Copy link
Member

@ymorin-orange ymorin-orange commented Aug 14, 2024

WIP: needs #154 to be merged first


Features:


  1. Prepare an OpenTelemetry collector on localhost:
    $ docker container run \
        --rm \
        -p 16686:16686 \
        -p 4318:4318 \
        jaegertracing/all-in-one:1.58
    
    then open a browser on the Jaegger UI:
    http://localhost:16686/
    
  2. Prepare an MQTT broker on localhost (adapt based on your distribution):
    $ sudo systemctl start mosquitto.service
    and then start an MQTT client to dump the messages on the broker:
    $ mosquitto_sub -V 5 -t '#' -F '%j' |jq .
    
  3. Start a gpsd daemon
    1. create a fake NEMA log, e.g. in file NMEA.log, e.g. the sample available
      on wikipedia
    2. start a gpsd daemon sending fake data:
      $ TMPDIR=/tmp gpsfake -q -P 2947 -u -n -c 0.1 NMEA.log
  4. Test IoT3 Core SDK:
    1. if your python is older than 3.11, install an environment with python 3.11
      (you'll need to have a development environment with gcc and at least libffi-dev
      and libssl-dev installed; adapt to your distribution):
      $ wget https://www.python.org/ftp/python/3.11.9/Python-3.11.9.tar.xz
      $ tar xJf Python-3.11.9.tar.xz
      $ cd Python-3.11.9
      $ ./configure --prefix "${HOME}/tmp/python/3.11" --with-openssl=/usr
      $ make install
      $ export PATH="${HOME}/tmp/python/3.11/bin:${PATH}"
    2. create a /venv/ in a writable location, and activate it:
      $ python3.11 -m venv ~/tmp/its
      $ . ~/tmp/its/bin/activate
    3. install the ITS components:
      (venv) cd python
      (venv) pip3 --disable-pip-version-check install \
              --no-binary ':all:' \
              ./iot3 \
              ./its-interqueuemanager \
              ./its-quadkeys \
              ./its-status \
              ./its-vehicle
      Note: its-info is not modified, so tested is not needed, so
      it's not istalled.
    4. test the its-status component:
      • create a configuration file, e.g. /tmp/its-status.cfg, with this content:
        [generic]
        id = test-status
        frequency = 1.0
        
        [stdout]
        enabled = false
        
        [mqtt]
        enabled = true
        host = localhost
        port = 1883
        username = USERNAME
        password = PASSWORD
        client_id = its-status
        topic = status/system
        
        [system]
        data-dir = /
        
        [gnss]
        host = localhost
        port = 2947
        persistence = 5.0
        Note: adapt USERNAME and PASSWORD with the appropriate credentials,
        and adapt host and port is you are usign a remote broker and/or it
        is listening on a non-standard port.
      • start its-status with that configuration file:
        (venv) $ its-status -c /tmp/its-status.cfg
    5. test the its-vehicle component:
      • create a configuration file, e.g. /tmp/its-vehicle.cfg, with this content:
        [general]
        instance-id = test-me
        type = CAM
        report-freq = 0.5
        topic-pub-prefix = PROJECT/inQueue/SUFFIX/
        topic-sub-prefix = PROJECT/outQueue/SUFFIX/
        depth = 22
        messages = cam cpm denm
        depth-sub-cam = 18
        depth-sub-cpm = 18
        depth-sub-denm = 15
        speed-thresholds = 8.33 19.44 27.78
        
        [telemetry]
        endpoint = http://localhost:4318
        
        [broker.main]
        host = localhost
        port = 1883
        username = USERNAME
        password = PASSWORD
        
        [gpsd]
        port = 2947
        persistence = 10.0
      • start its-vehicle with that configuration file:
        (venv) $ its-status -c /tmp/its-vehicle.cfg
    6. test the its-iqm component:
      • create a configuration file, e.g. /tmp/its-iqm.cfg, with this content:
        [general]
        instance-id = ora_geo_1234
        prefix = PROJECT
        suffix = SUFFIX
        
        [telemetry]
        endpoint = http://localhost:4318
        
        [local]
        host = localhost
        port = 1883
      • start its-iqm with that configuration file:
        (venv) $ its-iqm -c /tmp/its-iqm.cfg
  5. Look up traces in the Jaeger UI
  6. Stop the ITS components with Ctrl-C on each

Expected results

Pre-requisites are all met.

  1. The Jaegger UI is displayed in your browser
  2. The Mosqiutto server and clients are running
  3. The gpsd daemon is running
  4. The ITS components behave as expected;
    1. the contaienr starts
    2. the venv is activated
    3. the ITS components are installed
    4. the its-status component emits status messages, and the verbose dump
      from mosquitto_sub would look like:
      {
        "tst": "2024-09-20T08:01:04.047514Z+0200",
        "topic": "status/system",
        "qos": 0,
        "retain": 0,
        "payloadlen": 836,
        "payload": {
          "time_sources": null,
          "gnss": {
            "software": "gpsd 3.22",
            "model": "NMEA0183",
            "mode": 3
          },
          "cellular": [],
          "version": "1.2.0",
          "type": "status",
          "id": "test-status",
          "system": {
            "type": "obu",
            "hardware": "Unknown",
            "os_release": {
              "PRETTY_NAME": "Ubuntu 22.04.5 LTS",
              "NAME": "Ubuntu",
              "VERSION_ID": "22.04",
              "VERSION": "22.04.5 LTS (Jammy Jellyfish)",
              "VERSION_CODENAME": "jammy",
              "ID": "ubuntu",
              "ID_LIKE": "debian",
              "HOME_URL": "https://www.ubuntu.com/",
              "SUPPORT_URL": "https://help.ubuntu.com/",
              "BUG_REPORT_URL": "https://bugs.launchpad.net/ubuntu/",
              "PRIVACY_POLICY_URL": "https://www.ubuntu.com/legal/terms-and-policies/privacy-policy",
              "UBUNTU_CODENAME": "jammy"
            },
            "cpu_load": [
              0.650390625,
              0.8369140625,
              0.9921875
            ],
            "memory": [
              67095187456,
              53034876928
            ],
            "storage": [
              981132795904,
              506785951744
            ]
          },
          "timestamp": 1726812064.0466053
        }
      }
    5. the its-vehicle component emits status messages, and the verbose dump
      from mosquitto_sub would look like (notice the traceparent user
      property):
      {
        "tst": "2024-09-20T08:05:52.970202Z+0200",
        "topic": "PROJECT/inQueue/SUFFIX/cam/test-me/1/2/0/2/2/2/0/3/0/2/2/3/0/2/2/1/0/3/1/0/3/3",
        "qos": 0,
        "retain": 0,
        "payloadlen": 641,
        "properties": {
          "user-properties": {
            "traceparent": "00-057264776dc53a957fbb14530684cc45-47096d87822883fa-00"
          }
        },
        "payload": {
          "type": "cam",
          "origin": "self",
          "version": "1.1.3",
          "source_uuid": "test-me",
          "timestamp": 1726812352969,
          "message": {
            "protocol_version": 1,
            "station_id": 7603010,
            "generation_delta_time": 47411,
            "basic_container": {
              "station_type": 5,
              "reference_position": {
                "latitude": 436189667,
                "longitude": 15019833,
                "altitude": 0
              },
              "confidence": {
                "position_confidence_ellipse": {
                  "semi_major_confidence": 10,
                  "semi_minor_confidence": 50,
                  "semi_major_orientation": 1
                },
                "altitude": 1
              }
            },
            "high_frequency_container": {
              "heading": 3007,
              "speed": 998,
              "longitudinal_acceleration": 161,
              "drive_direction": 0,
              "vehicle_length": 40,
              "vehicle_width": 20,
              "confidence": {
                "heading": 2,
                "speed": 3,
                "vehicle_length": 0
              }
            }
          }
        }
      }
    6. the its-iqm component emits status messages, and the verbose dump from
      mosquitto_sub would look like (notice the traceparent user property,
      and the different topics: inQueue, outQueue, and interQuweue):
      {
        "tst": "2024-09-20T08:08:49.388984Z+0200",
        "topic": "PROJECT/inQueue/SUFFIX/cam/test-me/1/2/0/2/2/2/0/3/0/2/2/3/0/2/0/2/2/3/0/0/2/3",
        "qos": 0,
        "retain": 0,
        "payloadlen": 641,
        "properties": {
          "user-properties": {
            "traceparent": "00-e6386928b78d3f87f403ef63ce71c33e-4c1e46c2e528c427-00"
          }
        },
        "payload": {
          "type": "cam",
          "origin": "self",
          "version": "1.1.3",
          "source_uuid": "test-me",
          "timestamp": 1726812529387,
          "message": {
            "protocol_version": 1,
            "station_id": 7603010,
            "generation_delta_time": 27284,
            "basic_container": {
              "station_type": 5,
              "reference_position": {
                "latitude": 436209667,
                "longitude": 14956333,
                "altitude": 0
              },
              "confidence": {
                "position_confidence_ellipse": {
                  "semi_major_confidence": 10,
                  "semi_minor_confidence": 50,
                  "semi_major_orientation": 1
                },
                "altitude": 1
              }
            },
            "high_frequency_container": {
              "heading": 2729,
              "speed": 998,
              "longitudinal_acceleration": 161,
              "drive_direction": 0,
              "vehicle_length": 40,
              "vehicle_width": 20,
              "confidence": {
                "heading": 2,
                "speed": 3,
                "vehicle_length": 0
              }
            }
          }
        }
      }
      {
        "tst": "2024-09-20T08:08:49.390629Z+0200",
        "topic": "PROJECT/outQueue/SUFFIX/cam/test-me/1/2/0/2/2/2/0/3/0/2/2/3/0/2/0/2/2/3/0/0/2/3",
        "qos": 0,
        "retain": 0,
        "payloadlen": 641,
        "properties": {
          "user-properties": {
            "traceparent": "00-f431be1d1d66f07b110507d58185a3fd-4851c79cb4026051-00"
          }
        },
        "payload": {
          "type": "cam",
          "origin": "self",
          "version": "1.1.3",
          "source_uuid": "test-me",
          "timestamp": 1726812529387,
          "message": {
            "protocol_version": 1,
            "station_id": 7603010,
            "generation_delta_time": 27284,
            "basic_container": {
              "station_type": 5,
              "reference_position": {
                "latitude": 436209667,
                "longitude": 14956333,
                "altitude": 0
              },
              "confidence": {
                "position_confidence_ellipse": {
                  "semi_major_confidence": 10,
                  "semi_minor_confidence": 50,
                  "semi_major_orientation": 1
                },
                "altitude": 1
              }
            },
            "high_frequency_container": {
              "heading": 2729,
              "speed": 998,
              "longitudinal_acceleration": 161,
              "drive_direction": 0,
              "vehicle_length": 40,
              "vehicle_width": 20,
              "confidence": {
                "heading": 2,
                "speed": 3,
                "vehicle_length": 0
              }
            }
          }
        }
      }
      {
        "tst": "2024-09-20T08:08:49.390795Z+0200",
        "topic": "PROJECT/interQueue/SUFFIX/cam/test-me/1/2/0/2/2/2/0/3/0/2/2/3/0/2/0/2/2/3/0/0/2/3",
        "qos": 0,
        "retain": 0,
        "payloadlen": 641,
        "properties": {
          "user-properties": {
            "traceparent": "00-f431be1d1d66f07b110507d58185a3fd-2a7a8db15dec456d-00"
          }
        },
        "payload": {
          "type": "cam",
          "origin": "self",
          "version": "1.1.3",
          "source_uuid": "test-me",
          "timestamp": 1726812529387,
          "message": {
            "protocol_version": 1,
            "station_id": 7603010,
            "generation_delta_time": 27284,
            "basic_container": {
              "station_type": 5,
              "reference_position": {
                "latitude": 436209667,
                "longitude": 14956333,
                "altitude": 0
              },
              "confidence": {
                "position_confidence_ellipse": {
                  "semi_major_confidence": 10,
                  "semi_minor_confidence": 50,
                  "semi_major_orientation": 1
                },
                "altitude": 1
              }
            },
            "high_frequency_container": {
              "heading": 2729,
              "speed": 998,
              "longitudinal_acceleration": 161,
              "drive_direction": 0,
              "vehicle_length": 40,
              "vehicle_width": 20,
              "confidence": {
                "heading": 2,
                "speed": 3,
                "vehicle_length": 0
              }
            }
          }
        }
      }
  5. The Jaegger UI displays traces for the its-vehicle and its-interqueuemanager
    services, with appropriate links between traces.
  6. The ITS components all stop

Although the unix socket transport does not require a TCP port,
paho-mqtt expexts that a valid TCP port be specified when connecting.

Technically, specifying a port is not necessary in that case, so we
could in theory change our call to connect_async() to not pass a port
at al. However, that would make the code a bit more complex.

So, to simplify things, just use a valid TCP port, i.e. one that is
strictly greater than 0. We could have decided to use the default port,
1883, but that would be a bit misleading. Instead, we just use 1, which
is odd enough that it will at least raise an eyebrow to an unsuspecting
reviewer.

Signed-off-by: Yann E. MORIN <[email protected]>
@tigroo tigroo removed their request for review September 11, 2024 07:49
@tigroo tigroo added enhancement New feature or request Python Python code labels Sep 11, 2024
@tigroo tigroo added this to the Sprint 2 milestone Sep 11, 2024
The unsubscribe() method expects keyword arguments, not positional ones.

Signed-off-by: Yann E. MORIN <[email protected]>
The vareious ITS clients (its-vehicle, its-iqm...) currently use the
APIs of paho.mqtt 1.6.1, while the newly-introduce IoT3 Core SDK uses
those of 2.1.0.

In paho.mqtt 2.0.x, there was a breaking API change, so a client written
against paho.mqtt 1.6.1 (or earlier) could not be used as-is with
paho.mqtt 2.0.x.

but in paho.mqtt 2.1.0, there was another API change that made it
possible to use clients written against 1.6.1, without any modification,
while also alowing clients written againt the 2.0.0 API as well.

So we can accept anything from 1.6.1 onward, except for versions 2.0.x.

Signed-off-by: Yann E. MORIN <[email protected]>
Signed-off-by: Yann E. MORIN <[email protected]>
Signed-off-by: Yann E. MORIN <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request Python Python code
Projects
Status: In Progress
2 participants