Skip to content

Commit b4bc5f1

Browse files
authored
Edge Impulse container POC (#5)
1 parent 93b0079 commit b4bc5f1

File tree

9 files changed

+108
-9
lines changed

9 files changed

+108
-9
lines changed
Binary file not shown.

src/appslab/modules/dbstorage/module_compose.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ services:
44
ports:
55
- "${BIND_ADDRESS:-127.0.0.1}:${BIND_PORT:-8086}:8086"
66
volumes:
7-
- ./influxdb_data:/app/dbstorage/data
7+
- "${APP_PATH:-.}/influx-data:/var/lib/influxdb2"
88
environment:
99
DOCKER_INFLUXDB_INIT_MODE: setup
1010
DOCKER_INFLUXDB_INIT_USERNAME: "${USERNAME:-admin}"
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
name: db_storage
22
module_description: "Simplified database storage layer for Arduino sensor data"
3+
require_container: true
4+
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import logging
2+
import requests
3+
from appslab.core import load_module_compose_file, parse_docker_compose_variable
4+
import logging
5+
import io
6+
7+
logger = logging.getLogger(__name__)
8+
9+
class EdgeImpulseObjectDetection:
10+
def __init__(self):
11+
infra = load_module_compose_file(self.__class__)
12+
for k, v in infra['services'].items():
13+
self.host = k
14+
self.infra = v
15+
break # Only one service is expected
16+
17+
self.port = parse_docker_compose_variable(self.infra['ports'][0])[1][1] # Get the port, discard the host
18+
self.url = f"http://{self.host}:{self.port}/api/image"
19+
logger.info(f"[{self.__class__.__name__}] Host: {self.host} - Ports: {self.infra['ports']} - URL: {self.url}")
20+
21+
def detect_from_file(self, image_path :str) -> dict:
22+
if not image_path or image_path == "":
23+
return None
24+
with open(image_path, 'rb') as f:
25+
try:
26+
return self.detect(image_bytes = f.read(), image_type = image_path.split('.')[-1])
27+
except Exception as e:
28+
logger.error(f"Error: {e}")
29+
return None
30+
31+
def detect(self, image_bytes, image_type:str = "jpg") -> dict:
32+
if not image_bytes or not image_type:
33+
return None
34+
if image_type not in ["jpg", "jpeg", "png"]:
35+
logger.warning(f"[{self.__class__.__name__}] Invalid image type: {image_type}. Discarding image.")
36+
return None
37+
elif image_type == "jpg":
38+
image_type = "jpeg"
39+
40+
try:
41+
logger.debug(f"[{self.__class__.__name__}] Detecting image of type: {image_type} -> {len(image_bytes)} bytes")
42+
43+
files = {'image': (f"image.{image_type}", io.BytesIO(image_bytes), f"image/{image_type}")}
44+
response = requests.post(self.url, files=files)
45+
46+
except Exception as e:
47+
logger.error(f"[{self.__class__.__name__}] Error: {e}")
48+
return None
49+
50+
# Check the response
51+
if response.status_code == 200:
52+
return response.json()
53+
else:
54+
logger.warning(f"[{self.__class__}] error: {response.status_code}. Message: {response.text}")
55+
return None
56+
57+
def process(self, item):
58+
if isinstance(item, str):
59+
return self.parse(item)
60+
elif isinstance(item, dict) and 'image' in item and item['image'] != "":
61+
image = item['image']
62+
image_type = image.split('.')[-1]
63+
return self.detect(image, image_type.lower())
64+
65+
return item # No processing needed
66+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
services:
2+
ei-inference-classification:
3+
image: public.ecr.aws/g7a8t7v6/inference-container:48cd3f0d76c701a6070a27a8d9487d1733c155aa
4+
restart: unless-stopped
5+
ports:
6+
- ${BIND_ADDRESS:-127.0.0.1}:${BIND_PORT:-1337}:1337
7+
command: ["--api-key", "${EI_PROJECT_API_KEY:-x}", "--force-variant", "float32", "--force-engine", "tflite", "--run-http-server", "1337"]
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
name: edge_impulse_classification
2+
module_description: "Image classification using Edge Impulse"
3+
require_container: true
4+
configuration_variables:
5+
- name: EI_PROJECT_API_KEY
6+
description: "Edge Impulse project API key"
7+
default_value:
8+
required: true

src/appslab/modules/log/__init__.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,33 @@
22
import logging
33

44
logger = logging.getLogger(__name__)
5-
65
class Log:
7-
def __init__(self):
6+
def __init__(self, level = logging.INFO):
7+
logging.basicConfig(level=level)
88
pass
99

10+
def info(self, msg):
11+
logger.info(msg)
12+
13+
def debug(self, msg):
14+
logger.debug(msg)
15+
16+
def error(self, msg):
17+
logger.error(msg)
18+
19+
def warning(self, msg):
20+
logger.warning(msg)
21+
1022
def print(self, item):
23+
self.consume(item)
24+
25+
def consume(self, item):
1126
if item == None:
1227
return None
1328

1429
logger.info(item)
1530

1631
return item
1732

18-
def consume(self, item):
19-
self.print(item)
20-
2133
def process(self, item):
22-
self.print(item)
23-
return item
34+
return self.consume(item)

src/appslab/modules/mqtt/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ def on_connect(client, userdata, flags, reason_code, properties):
3030
MAX_RECONNECT_DELAY = 60
3131

3232
def on_disconnect(client, userdata, flags, reason_code, properties):
33+
if reason_code == 0:
34+
logger.info("MQTT client disconnected gracefully")
35+
return
36+
3337
logger.info("Disconnected with result code: %s", reason_code)
3438
reconnect_count, reconnect_delay = 0, FIRST_RECONNECT_DELAY
3539
while reconnect_count < MAX_RECONNECT_COUNT:
@@ -93,7 +97,7 @@ def __init__(self, broker_address:str, broker_port:int, topic:str, username:str,
9397

9498
self.client.on_message = self._on_message
9599

96-
err = self.client.connect(broker_address, broker_port, 60)
100+
self.client.connect(broker_address, broker_port, 60)
97101

98102
self.client.loop_start()
99103

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
name: object_detection
22
module_description: "Simple module for general purpose object detection."
3+
require_container: true

0 commit comments

Comments
 (0)