Skip to content

Commit 356cbe7

Browse files
mirkoCrobumirkoCrobualessio-perugini
authored
Refactor: relocate assets from mbed to FileSystem
Co-authored-by: mirkoCrobu <mirkocrobu@NB-0531.localdomain> Co-authored-by: Alessio Perugini <alessio@perugini.xyz>
1 parent 047242a commit 356cbe7

File tree

133 files changed

+5423
-358
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

133 files changed

+5423
-358
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,4 @@ build/
3434
/arduino-app-cli
3535
/apps
3636
# temporary staging directories
37-
/debian/arduino-app-cli/home/
37+
/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/examples

cmd/arduino-app-cli/app/start.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ func startHandler(ctx context.Context, cfg config.Configuration, app app.Arduino
4444
servicelocator.GetBricksIndex(),
4545
app,
4646
cfg,
47+
servicelocator.GetStaticStore(),
4748
)
4849
for message := range stream {
4950
switch message.GetType() {

cmd/arduino-app-cli/daemon/daemon.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ func NewDaemonCmd(cfg config.Configuration, version string) *cobra.Command {
5555
servicelocator.GetBricksIndex(),
5656
servicelocator.GetAppIDProvider(),
5757
cfg,
58+
servicelocator.GetStaticStore(),
5859
)
5960
if err != nil {
6061
slog.Error("Failed to start default app", slog.String("error", err.Error()))

cmd/arduino-app-cli/internal/servicelocator/servicelocator.go

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -35,39 +35,18 @@ var (
3535
runnerVersion = "0.1.16"
3636

3737
GetBricksIndex = sync.OnceValue(func() *bricksindex.BricksIndex {
38-
var bIndex *bricksindex.BricksIndex
39-
if GetProvisioner().IsUsingDynamicProvision() {
40-
dynamicProvisionDir := GetProvisioner().DynamicProvisionDir()
41-
bIndex = f.Must(bricksindex.GenerateBricksIndexFromFile(dynamicProvisionDir))
42-
} else {
43-
bricksIndexContent := f.Must(GetStaticStore().GetBricksListFile())
44-
defer bricksIndexContent.Close()
45-
bIndex = f.Must(bricksindex.LoadBricksIndex(bricksIndexContent))
46-
}
47-
return bIndex
38+
return f.Must(bricksindex.GenerateBricksIndexFromFile(GetStaticStore().GetAssetsFolder()))
4839
})
4940

5041
GetModelsIndex = sync.OnceValue(func() *modelsindex.ModelsIndex {
51-
var mIndex *modelsindex.ModelsIndex
52-
if GetProvisioner().IsUsingDynamicProvision() {
53-
dynamicProvisionDir := GetProvisioner().DynamicProvisionDir()
54-
mIndex = f.Must(modelsindex.GenerateModelsIndexFromFile(dynamicProvisionDir))
55-
} else {
56-
modelsIndexContent := f.Must(GetStaticStore().GetModelsListFile())
57-
defer modelsIndexContent.Close()
58-
mIndex = f.Must(modelsindex.LoadModelsIndex(modelsIndexContent))
59-
}
60-
return mIndex
42+
return f.Must(modelsindex.GenerateModelsIndexFromFile(GetStaticStore().GetAssetsFolder()))
6143
})
6244

6345
GetProvisioner = sync.OnceValue(func() *orchestrator.Provision {
64-
pythonImage, usedPythonImageTag := getPythonImageAndTag()
65-
slog.Debug("Using pythonImage", slog.String("image", pythonImage))
66-
46+
pythonImage, _ := getPythonImageAndTag()
6747
return f.Must(orchestrator.NewProvision(
6848
GetDockerClient(),
69-
GetStaticStore(),
70-
usedPythonImageTag != runnerVersion,
49+
shouldUseDynamicProvisioning(),
7150
pythonImage,
7251
))
7352
})
@@ -102,7 +81,13 @@ var (
10281
})
10382

10483
GetStaticStore = sync.OnceValue(func() *store.StaticStore {
105-
return store.NewStaticStore(runnerVersion)
84+
var baseDir string
85+
if GetProvisioner().IsUsingDynamicProvision() {
86+
baseDir = GetProvisioner().DynamicProvisionDir().String()
87+
} else {
88+
baseDir = globalConfig.AssetsDir().Join(runnerVersion).String()
89+
}
90+
return store.NewStaticStore(baseDir)
10691
})
10792

10893
GetBrickService = sync.OnceValue(func() *bricks.Service {
@@ -136,3 +121,9 @@ func getPythonImageAndTag() (string, string) {
136121
}
137122
return pythonImage, usedPythonImageTag
138123
}
124+
125+
func shouldUseDynamicProvisioning() bool {
126+
pythonImage, usedPythonImageTag := getPythonImageAndTag()
127+
slog.Debug("Using pythonImage", slog.String("image", pythonImage))
128+
return usedPythonImageTag != runnerVersion
129+
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#!/bin/sh
22

3-
chown -R arduino:arduino /home/arduino/.config/arduino-app-cli/examples
3+
chown -R arduino:arduino /home/arduino/.config/arduino-app-cli
4+
chown -R arduino:arduino /home/arduino/.local/share/arduino-app-cli
45

56
systemctl enable arduino-app-cli
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
# air_quality_monitoring API Reference
2+
3+
## Index
4+
5+
- Class `AQILevel`
6+
- Class `AirQualityData`
7+
- Class `AirQualityMonitoring`
8+
- Class `AirQualityLookupError`
9+
10+
---
11+
12+
## `AQILevel` dataclass
13+
14+
```python
15+
class AQILevel()
16+
```
17+
18+
Data class to represent AQI levels.
19+
20+
### Attributes
21+
22+
- **min_value** (*int*): Minimum AQI value for the level.
23+
- **max_value** (*int*): Maximum AQI value for the level.
24+
- **description** (*str*): Description of the AQI level.
25+
- **color** (*str*): Color associated with the AQI level in hex.
26+
27+
28+
---
29+
30+
## `AirQualityData` dataclass
31+
32+
```python
33+
class AirQualityData()
34+
```
35+
36+
Data class to represent air quality data.
37+
38+
### Attributes
39+
40+
- **city** (*str*): Name of the city.
41+
- **lat** (*float*): Latitude of the city.
42+
- **lon** (*float*): Longitude of the city.
43+
- **url** (*str*): URL for more information about the air quality data.
44+
- **last_update** (*str*): Last update timestamp of the air quality data.
45+
- **aqi** (*int*): Air Quality Index value.
46+
- **dominantpol** (*str*): Dominant pollutant in the air.
47+
- **iaqi** (*dict*): Individual AQI values for various pollutants.
48+
49+
### Methods
50+
51+
#### `AirQualityData.pandas_dict()`
52+
53+
Return the data as a dictionary suitable for pandas DataFrame.
54+
55+
56+
---
57+
58+
## `AirQualityMonitoring` class
59+
60+
```python
61+
class AirQualityMonitoring(token: str)
62+
```
63+
64+
Class to get air quality data from AQICN API.
65+
66+
### Parameters
67+
68+
- **token** (*str*): API token for AQICN service.
69+
70+
### Raises
71+
72+
- **ValueError**: If the token is not provided.
73+
74+
### Methods
75+
76+
#### `AirQualityMonitoring.get_air_quality_by_city(city: str)`
77+
78+
Get air quality data by city name.
79+
80+
##### Parameters
81+
82+
- **city** (*str*): Name of the city.
83+
84+
##### Returns
85+
86+
- (*AirQualityData*): Air quality assembled data.
87+
88+
##### Raises
89+
90+
- **AirQualityLookupError**: If the API request fails.
91+
92+
#### `AirQualityMonitoring.get_air_quality_by_coords(latitude: float, longitude: float)`
93+
94+
Get air quality data by coordinates.
95+
96+
##### Parameters
97+
98+
- **latitude** (*float*): Latitude.
99+
- **longitude** (*float*): Longitude.
100+
101+
##### Returns
102+
103+
- (*AirQualityData*): Air quality assembled data.
104+
105+
##### Raises
106+
107+
- **AirQualityLookupError**: If the API request fails.
108+
109+
#### `AirQualityMonitoring.get_air_quality_by_ip()`
110+
111+
Get air quality data by IP address.
112+
113+
##### Returns
114+
115+
- (*AirQualityData*): Air quality assembled data.
116+
117+
##### Raises
118+
119+
- **AirQualityLookupError**: If the API request fails.
120+
121+
#### `AirQualityMonitoring.process(item: dict)`
122+
123+
Process the input dictionary to get air quality data.
124+
125+
##### Parameters
126+
127+
- **item** (*dict*): Input dictionary containing either 'city', 'latitude' and 'longitude', or 'ip'.
128+
129+
##### Returns
130+
131+
- (*dict*): Air quality data.
132+
133+
##### Raises
134+
135+
- **ValueError**: If the input dictionary is not valid.
136+
137+
#### `AirQualityMonitoring.assemble_data(data: dict)`
138+
139+
Create a payload for the air quality data.
140+
141+
##### Parameters
142+
143+
- **data** (*dict*): Air quality data.
144+
145+
##### Returns
146+
147+
- (*dict*): Payload with relevant air quality information.
148+
149+
#### `AirQualityMonitoring.map_aqi_level(aqi: int)`
150+
151+
Returns AQILevel class matching provided AQI.
152+
153+
154+
---
155+
156+
## `AirQualityLookupError` class
157+
158+
```python
159+
class AirQualityLookupError(message: str, status: str)
160+
```
161+
162+
Custom exception for air quality lookup errors.
163+
164+
### Parameters
165+
166+
- **message** (*str*): Error message.
167+
- **status** (*str*): Status of the error, defaults to None.
168+
169+
### Methods
170+
171+
#### `AirQualityLookupError.from_api_response(cls, data: dict)`
172+
173+
AirQualityLookupError error handling based on response provided by AQI API.
174+
175+
Documented errors:
176+
- {"status": "error", "data": "Invalid key"}
177+
- {"status": "error", "data": "Unknown station"}
178+
- {"status": "error", "data": "Over quota"}
179+
- {"status": "error", "data": "Invalid query"}
180+
- {"status": "error", "data": "Too Many Requests"}
181+
- {"status": "error", "data": "IP not allowed"}
182+
- {"status": "error", "data": "Unknown error"}
183+
- {"status": "error", "data": {"message": "..."}}
184+
185+
##### Parameters
186+
187+
- **data** (*dict*): Response data from the AQI API.
188+
189+
##### Returns
190+
191+
- (*AirQualityLookupError*): An instance of AirQualityLookupError with the error message and status.
192+
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# audio_classifier API Reference
2+
3+
## Index
4+
5+
- Class `AudioClassifierException`
6+
- Class `AudioClassifier`
7+
8+
---
9+
10+
## `AudioClassifierException` class
11+
12+
```python
13+
class AudioClassifierException()
14+
```
15+
16+
Custom exception for AudioClassifier errors.
17+
18+
19+
---
20+
21+
## `AudioClassifier` class
22+
23+
```python
24+
class AudioClassifier(mic: Microphone, confidence: float)
25+
```
26+
27+
AudioClassifier module for detecting sounds and classifying audio using a specified model.
28+
29+
### Parameters
30+
31+
- **mic** (*Microphone*): Microphone instance for audio input. If None, a default Microphone will be initialized.
32+
- **confidence** (*float*): Confidence level for detection. Default is 0.8 (80%).
33+
34+
### Raises
35+
36+
- **ValueError**: If the model information cannot be retrieved or if the model parameters are incomplete.
37+
38+
### Methods
39+
40+
#### `AudioClassifier.on_detect(class_name: str, callback: Callable[[], None])`
41+
42+
Register a callback function to be invoked when a specific class is detected.
43+
44+
##### Parameters
45+
46+
- **class_name** (*str*): The class to check for in the classification results.
47+
- **callback** (*callable*): a callback function to handle the keyword spotted.
48+
49+
#### `AudioClassifier.start()`
50+
51+
Start the AudioClassifier module and begin processing audio data.
52+
53+
#### `AudioClassifier.stop()`
54+
55+
Stop the AudioClassifier module and release resources.
56+
57+
#### `AudioClassifier.classify_from_file(audio_path: str, confidence: int)`
58+
59+
Classify audio from a file.
60+
61+
##### Parameters
62+
63+
- **audio_path** (*str*): Path to the audio file.
64+
- **confidence** (*int*): Confidence threshold for classification. If None, the default confidence level is used.
65+
66+
##### Returns
67+
68+
-: dict | None: Classification results or None if the path is invalid.
69+
70+
##### Raises
71+
72+
- **AudioClassifierException**: If the audio file cannot be read or processed.
73+

0 commit comments

Comments
 (0)