diff --git a/README.md b/README.md index 79b4c12..ae1340c 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ Component | Content | Comment/Status ----------|----------|--------------- [HVAC Service](hvac_service) | Python service example [Seat Service](seat_service) | C++ service example +[eCAL Provider](ecal2val) | Python provider for [eCAL](https://projects.eclipse.org/projects/automotive.ecal) ## Contribution diff --git a/ecal2val/README.md b/ecal2val/README.md new file mode 100644 index 0000000..f386934 --- /dev/null +++ b/ecal2val/README.md @@ -0,0 +1,53 @@ +# eCAL Feeder +The purpose of this implementation is to input data received via [eCAL](https://projects.eclipse.org/projects/automotive.ecal) into +[KUKSA Databroker](https://github.com/eclipse/kuksa.val/tree/master/kuksa_databroker). +The topics transmitted by eCAL are in the form of protobuf, and based on the VSS description and data outlined in this format, +it is possible to provide data to the databroker via kuksa_client. + + + +## Usage +1. Install Python requirements for both eCAL and KUKSA.val + +``` +sudo add-apt-repository ppa:ecal/ecal-5.12 +sudo apt-get update +sudo apt-get install ecal +sudo apt install python3-ecal5 + +pip install kuksa-client + +``` + +2. Generate proto_struct_pb2.py in proto directory with following method + +``` +sudo apt-get install protobuf-compiler + +protoc --python_out=. proto_struct.proto + +``` + +3. Use the following command to run the ecal2val.py + +``` +export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python + +python3 ecal2val.py + +``` + +This assumes a running `KUKSA.val` databroker at `127.0.0.1:55555`. + +4. For testing, run the mock_publisher.py + +``` +export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python + +python3 mock_publisher.py + +``` + +Modify proto file to utilize more specific information. + +This was successfully tested on Ubuntu 20.04 and eCAL 5.12. diff --git a/ecal2val/ecal2val.py b/ecal2val/ecal2val.py new file mode 100644 index 0000000..6d2ad12 --- /dev/null +++ b/ecal2val/ecal2val.py @@ -0,0 +1,64 @@ +#! /usr/bin/env python3 + +######################################################################## +# Copyright (c) 2024 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License 2.0 which is available at +# http://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +######################################################################## + +''' +Subscriber subscribing vss topics via ECAL communication +and sending it to KUKSA.val databroker. +''' + +import sys +import time + +import ecal.core.core as ecal_core +from ecal.core.subscriber import ProtoSubscriber + +import proto.proto_struct_pb2 as proto_struct_pb2 + +from kuksa_client.grpc import Datapoint +from kuksa_client.grpc import DataEntry +from kuksa_client.grpc import EntryUpdate +from kuksa_client.grpc import Field +from kuksa_client.grpc import VSSClient + + +ecal_core.initialize(sys.argv, "ecal2val") + +sub = ProtoSubscriber("vss_topic", proto_struct_pb2.DataEntry) + +''' +This callback function subscribes topics +and writes the data to the databroker. +''' + + +def callback(topic_name, msg, time): + with VSSClient('127.0.0.1', 55555) as client: + entry = DataEntry( + path=msg.path, + value=Datapoint(value=eval(f"msg.value.{msg.data_type}")), + ) + updates = (EntryUpdate(entry, (Field.VALUE,)),) + + client.set(updates=updates) + + print(f'{msg.path} subscribed & written') + + +sub.set_callback(callback) + +while ecal_core.ok(): + time.sleep(1) + +ecal_core.finalize() diff --git a/ecal2val/mock_data.txt b/ecal2val/mock_data.txt new file mode 100644 index 0000000..9bf00de --- /dev/null +++ b/ecal2val/mock_data.txt @@ -0,0 +1,20 @@ +Vehicle.Speed 1.0 float +Vehicle.Chassis.SteeringWheel.Angle -40 int32 +Vehicle.Speed 1.2 float +Vehicle.Chassis.SteeringWheel.Angle -30 int32 +Vehicle.Speed 1.4 float +Vehicle.Chassis.SteeringWheel.Angle -20 int32 +Vehicle.Speed 1.6 float +Vehicle.Chassis.SteeringWheel.Angle -10 int32 +Vehicle.Speed 1.8 float +Vehicle.Chassis.SteeringWheel.Angle 0 int32 +Vehicle.Speed 2.0 float +Vehicle.Chassis.SteeringWheel.Angle 10 int32 +Vehicle.Speed 2.2 float +Vehicle.Chassis.SteeringWheel.Angle 20 int32 +Vehicle.Speed 2.4 float +Vehicle.Chassis.SteeringWheel.Angle 30 int32 +Vehicle.Speed 2.6 float +Vehicle.Chassis.SteeringWheel.Angle 40 int32 +Vehicle.Speed 2.8 float +Vehicle.Chassis.SteeringWheel.Angle 50 int32 diff --git a/ecal2val/mock_publisher.py b/ecal2val/mock_publisher.py new file mode 100644 index 0000000..803b34b --- /dev/null +++ b/ecal2val/mock_publisher.py @@ -0,0 +1,77 @@ +#! /usr/bin/env python3 + +######################################################################## +# Copyright (c) 2024 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License 2.0 which is available at +# http://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +######################################################################## + +''' +Publisher publishing vss topics via eCAL communication. +''' + +import sys +import time + +import ecal.core.core as ecal_core +from ecal.core.publisher import ProtoPublisher + +import proto.proto_struct_pb2 as proto_struct_pb2 + + +def string(value): + return str(value) + + +def int32(value): + return int(value) + + +def int64(value): + return int(value) + + +def uint32(value): + return int(value) + + +def uint64(value): + return int(value) + + +def double(value): + return float(value) + + +ecal_core.initialize(sys.argv, "ecal2val") + +pub = ProtoPublisher("vss_topic", proto_struct_pb2.DataEntry) + +''' +Reads arbitrary data from 'mock_data.txt' +and publishes it in the form of a protobuf message. +''' + +while ecal_core.ok(): + with open("mock_data.txt", 'r', encoding='utf-8') as file: + for line in file: + path, value, data_type = line.split() + + entry = proto_struct_pb2.DataEntry() + entry.path = path + exec(f"entry.value.{data_type} = {data_type}(value)") + entry.data_type = data_type + + pub.send(entry) + print(f"{path} published") + + time.sleep(1) + +ecal_core.finalize() diff --git a/ecal2val/proto/proto_struct.proto b/ecal2val/proto/proto_struct.proto new file mode 100644 index 0000000..f7b71f0 --- /dev/null +++ b/ecal2val/proto/proto_struct.proto @@ -0,0 +1,35 @@ +/******************************************************************************** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License 2.0 which is available at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +syntax = "proto3"; + +package proto_struct; + +message DataEntry { + string path = 1; + DataPoint value = 2; + string data_type = 3; +} + +message DataPoint { + oneof value { + string string = 1; + bool bool = 2; + sint32 int32 = 3; + sint64 int64 = 4; + uint32 uint32 = 5; + uint64 uint64 = 6; + float float = 7; + double double = 8; + } +}