Skip to content

Commit

Permalink
Add event record service
Browse files Browse the repository at this point in the history
This service is to read the power up, power loss, eio, tilt, uncover,
and watchdog reset events, then writes them into syslog and makes them
be readable for journald.

Signed-off-by: Li Hua Qian <[email protected]>
  • Loading branch information
huaqianli authored and BaochengSu committed Dec 2, 2023
1 parent 62ec1d9 commit a34ec4f
Show file tree
Hide file tree
Showing 16 changed files with 879 additions and 0 deletions.
75 changes: 75 additions & 0 deletions recipes-app/iot2050-event-record/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# IOT2050 Event Record

IOT2050 Event Record is using for reading and recording events, such as
power up, power loss, tilted, uncovered, watchdog reset and eio events.

The core is a RPC service implemented with the help of gPRC.

In addition:
- A event-serve service for writing and reading syslog.
- A event-record service for recording events.

# Sensor events

In default, the sensor events, i.e. tilted and uncovered events, are disabled.
If enabling logging of sensor events is expected, please create a systemd
drop-in for `iot2050-event-record.service`, as follows:

```sh
cp /usr/lib/iot2050/event/iot2050-event-record.conf /etc/systemd/system/iot2050-event-record.service.d/
```

# Watchdog events example

If watchdog events recording is expected, please run the following commands,
or write a new one referring to this example.
```sh
python3 /usr/lib/iot2050/event/iot2050-event-wdt.py
```

## How to record a new event?

First, please link the `EventInterface` to the customized application.
```sh
# In IOT DUT
ln -s /usr/lib/iot2050/event/gRPC/EventInterface /path/to/customized-app/gRPC/EventInterface

# In Source code
ln -s recipes-app/iot2050-event-record/files/gRPC/EventInterface /path/to/customized-app/gRPC/EventInterface
```

Then, use the `Write` and `Read` functions to communicate with
`iot2050-event-serve.service`, as follows:

```py
import grpc
from gRPC.EventInterface.iot2050_event_pb2 import (
WriteRequest,
ReadRequest
)
from gRPC.EventInterface.iot2050_event_pb2_grpc import EventRecordStub


def write_event(event_type, event):
with grpc.insecure_channel(iot2050_event_api_server) as channel:
stub = EventRecordStub(channel)
response = stub.Write(WriteRequest(event_type=event_type, event=event))

if response.status:
print(f'Event Record writes event result: {response.status}')
print(f'Event Record writes event message: {response.message}')

def read_event(event_type):
with grpc.insecure_channel(iot2050_event_api_server) as channel:
stub = EventRecordStub(channel)
response = stub.Read(ReadRequest(event_type=event_type))
return response.event
```

And, please find the api definition in `gRPC/EventInterface/iot2050-event.proto`.

## Regenerate the gRPC python modules if proto file changes:

```sh
python3 -m grpc_tools.protoc -I. --python_out=. --pyi_out=. --grpc_python_out=. gRPC/EventInterface/iot2050-event.proto
```
1 change: 1 addition & 0 deletions recipes-app/iot2050-event-record/files/gRPC/EIOManager
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright (c) Siemens AG, 2023
*
* Authors:
* Li Hua Qian <[email protected]>
*
* SPDX-License-Identifier: MIT
*/

syntax = "proto3";

package eventrecord;

service EventRecord {
rpc Write (WriteRequest) returns (WriteReply) {}
rpc Read (ReadRequest) returns (ReadReply) {}
}

/* ----------------- Write event ----------------- */
/* WriteRequest
* - event_type: a string to present event type
* - "IOT2050_EVENT.xxx" means IOT2050 standard events
* - "" or other strings mean customized events
* - event: the event content to write
*/
message WriteRequest {
string event_type = 1;
string event = 2;
}

/* WriteReply
* - status: 0 means successful
* others mean error
* - message: the detail write message
*/
message WriteReply {
int32 status = 1;
string message = 2;
}

/* ----------------- Read event ----------------- */
/* ReadRequest
* - event_type: a string to present event type
* - "IOT2050_EVENT.xxx" means IOT2050 standard events
* - "" means to all types of events
*/
message ReadRequest {
string event_type = 1;
}

/* ReadReply
* - status: 0 means successful
* others mean error
* - message: the detail write message
* - event: the read back event content
*/
message ReadReply {
int32 status = 1;
string message = 2;
string event = 3;
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from typing import ClassVar as _ClassVar, Optional as _Optional

DESCRIPTOR: _descriptor.FileDescriptor

class WriteRequest(_message.Message):
__slots__ = ["event_type", "event"]
EVENT_TYPE_FIELD_NUMBER: _ClassVar[int]
EVENT_FIELD_NUMBER: _ClassVar[int]
event_type: str
event: str
def __init__(self, event_type: _Optional[str] = ..., event: _Optional[str] = ...) -> None: ...

class WriteReply(_message.Message):
__slots__ = ["status", "message"]
STATUS_FIELD_NUMBER: _ClassVar[int]
MESSAGE_FIELD_NUMBER: _ClassVar[int]
status: int
message: str
def __init__(self, status: _Optional[int] = ..., message: _Optional[str] = ...) -> None: ...

class ReadRequest(_message.Message):
__slots__ = ["event_type"]
EVENT_TYPE_FIELD_NUMBER: _ClassVar[int]
event_type: str
def __init__(self, event_type: _Optional[str] = ...) -> None: ...

class ReadReply(_message.Message):
__slots__ = ["status", "message", "event"]
STATUS_FIELD_NUMBER: _ClassVar[int]
MESSAGE_FIELD_NUMBER: _ClassVar[int]
EVENT_FIELD_NUMBER: _ClassVar[int]
status: int
message: str
event: str
def __init__(self, status: _Optional[int] = ..., message: _Optional[str] = ..., event: _Optional[str] = ...) -> None: ...
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
"""Client and server classes corresponding to protobuf-defined services."""
import grpc

from gRPC.EventInterface import iot2050_event_pb2 as gRPC_dot_EventInterface_dot_iot2050__event__pb2


class EventRecordStub(object):
"""Missing associated documentation comment in .proto file."""

def __init__(self, channel):
"""Constructor.
Args:
channel: A grpc.Channel.
"""
self.Write = channel.unary_unary(
'/eventrecord.EventRecord/Write',
request_serializer=gRPC_dot_EventInterface_dot_iot2050__event__pb2.WriteRequest.SerializeToString,
response_deserializer=gRPC_dot_EventInterface_dot_iot2050__event__pb2.WriteReply.FromString,
)
self.Read = channel.unary_unary(
'/eventrecord.EventRecord/Read',
request_serializer=gRPC_dot_EventInterface_dot_iot2050__event__pb2.ReadRequest.SerializeToString,
response_deserializer=gRPC_dot_EventInterface_dot_iot2050__event__pb2.ReadReply.FromString,
)


class EventRecordServicer(object):
"""Missing associated documentation comment in .proto file."""

def Write(self, request, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')

def Read(self, request, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')


def add_EventRecordServicer_to_server(servicer, server):
rpc_method_handlers = {
'Write': grpc.unary_unary_rpc_method_handler(
servicer.Write,
request_deserializer=gRPC_dot_EventInterface_dot_iot2050__event__pb2.WriteRequest.FromString,
response_serializer=gRPC_dot_EventInterface_dot_iot2050__event__pb2.WriteReply.SerializeToString,
),
'Read': grpc.unary_unary_rpc_method_handler(
servicer.Read,
request_deserializer=gRPC_dot_EventInterface_dot_iot2050__event__pb2.ReadRequest.FromString,
response_serializer=gRPC_dot_EventInterface_dot_iot2050__event__pb2.ReadReply.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
'eventrecord.EventRecord', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))


# This class is part of an EXPERIMENTAL API.
class EventRecord(object):
"""Missing associated documentation comment in .proto file."""

@staticmethod
def Write(request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None):
return grpc.experimental.unary_unary(request, target, '/eventrecord.EventRecord/Write',
gRPC_dot_EventInterface_dot_iot2050__event__pb2.WriteRequest.SerializeToString,
gRPC_dot_EventInterface_dot_iot2050__event__pb2.WriteReply.FromString,
options, channel_credentials,
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)

@staticmethod
def Read(request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None):
return grpc.experimental.unary_unary(request, target, '/eventrecord.EventRecord/Read',
gRPC_dot_EventInterface_dot_iot2050__event__pb2.ReadRequest.SerializeToString,
gRPC_dot_EventInterface_dot_iot2050__event__pb2.ReadReply.FromString,
options, channel_credentials,
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# If you want to enable logging of sensor events, i.e. tilted and uncovered events.
# Please copy this file to /etc/systemd/system/iot2050-event-record.service.d/.

[Service]
Environment="RECORD_SENSOR_EVENTS=True"
Loading

0 comments on commit a34ec4f

Please sign in to comment.