Skip to content

Commit 00c96bc

Browse files
authored
Merge pull request #10 from FarmBot-Labs/jmash/verbosity
Jmash/verbosity
2 parents 636234d + b3539c9 commit 00c96bc

14 files changed

+164
-82
lines changed

README.md

+28-2
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,32 @@ bot.set_verbosity(2)
8484
| `1` The name of the function will be output. | `e_stop called` |
8585
| `2` The name of the function will be output with additional information about the return value. | `Triggered device emergency stop at: 2024-08-21 11:16:18.547813` |
8686

87+
### Test 1: Add a new plant to your garden
88+
89+
This test will help familiarize you with sending commands via the [API](https://developer.farm.bot/docs/rest-api).
90+
```
91+
new_cabbage = {
92+
"name": "Cabbage", # Point name
93+
"pointer_type": "Plant", # Point type
94+
"x": 400, # x-coordinate
95+
"y": 300, # y-coordinate
96+
"z": 0, # z-coordinate
97+
"openfarm_slug": "cabbage", # Plant type
98+
"plant_stage": "planned", # Point status
99+
}
100+
101+
bot.add_info("points", new_cabbage) # Add plant to endpoint
102+
```
103+
104+
### Test 2: Turn your LED strip on and off
105+
106+
This test will help familiarize you with sending commands via the [Message Broker](https://developer.farm.bot/docs/message-broker).
107+
```
108+
bot.on(7) # Turn ON pin 7 (LED strip)
109+
bot.wait(2000) # Wait 2000 milliseconds
110+
bot.off(7) # Turn OFF pin 7 (LED strip)
111+
```
112+
87113
## :compass: Functions
88114

89115
```
@@ -159,7 +185,7 @@ sidecar-starter-pack/
159185
> Making requests other than `GET` to the API will permanently alter the data in your account. `DELETE` and `POST` requests may destroy data that cannot be recovered. Altering data through the API may cause account instability.
160186
161187
> [!NOTE]
162-
> Not sure which endpoint to access? [Find the list here](https://developer.farm.bot/v15/docs/web-app/api-docs).
188+
> Not sure which endpoint to access? [Find the list here](https://developer.farm.bot/docs/api-docs).
163189
164190
| class `Information()` | Description |
165191
| :--- | :--- |
@@ -239,7 +265,7 @@ sidecar-starter-pack/
239265
### Formatting message broker messages
240266

241267
> [!NOTE]
242-
> Messages sent via the message broker contain [CeleryScript nodes](https://developer.farm.bot/v15/docs/celery-script/nodes.html) which require special formatting.
268+
> Messages sent via the message broker contain [CeleryScript nodes](https://developer.farm.bot/docs/celery-script/nodes.html) which require special formatting.
243269
244270
```
245271
message = {

functions/authentication.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ def get_token(self, email, password, server="https://my.farm.bot"):
2525
if response.status_code == 200:
2626
self.state.token = response.json()
2727
self.state.error = None
28+
self.state.print_status("get_token()", description=f"Sucessfully fetched token from {server}.")
2829
return response.json()
2930
elif response.status_code == 404:
3031
self.state.error = "HTTP ERROR: The server address does not exist."
@@ -44,19 +45,21 @@ def get_token(self, email, password, server="https://my.farm.bot"):
4445
self.state.error = f"DNS ERROR: An unexpected error occurred: {str(e)}"
4546

4647
self.state.token = None
48+
self.state.print_status("get_token()", description=self.state.error)
4749
return self.state.error
4850

4951
def check_token(self):
5052
"""Ensure the token persists throughout sidecar."""
5153

5254
if self.state.token is None:
53-
print("ERROR: You have no token, please call `get_token` using your login credentials and the server you wish to connect to.")
55+
self.state.print_status("check_token()", description="ERROR: You have no token, please call `get_token` using your login credentials and the server you wish to connect to.")
5456
sys.exit(1)
5557

5658
return
5759

5860
def request_handling(self, response):
5961
"""Handle errors associated with different endpoint errors."""
62+
6063
error_messages = {
6164
404: "The specified endpoint does not exist.",
6265
400: "The specified ID is invalid or you do not have access to it.",
@@ -66,6 +69,7 @@ def request_handling(self, response):
6669

6770
# Handle HTTP status codes
6871
if response.status_code == 200:
72+
self.state.print_status("check_token()", description="Successfully sent request via API.")
6973
return 200
7074
elif 400 <= response.status_code < 500:
7175
self.state.error = json.dumps(f"CLIENT ERROR {response.status_code}: {error_messages.get(response.status_code, response.reason)}", indent=2)
@@ -74,6 +78,7 @@ def request_handling(self, response):
7478
else:
7579
self.state.error = json.dumps(f"UNEXPECTED ERROR {response.status_code}: {response.text}", indent=2)
7680

81+
self.state.print_status("request_handling()", description=self.state.error)
7782
return
7883

7984
def request(self, method, endpoint, database_id, payload=None):
@@ -96,6 +101,8 @@ def request(self, method, endpoint, database_id, payload=None):
96101

97102
if self.request_handling(response) == 200:
98103
self.state.error = None
104+
self.state.print_status("request()", description="Successfully returned request contents.")
99105
return response.json()
100106
else:
107+
self.state.print_status("request()", description="There was an error processing the request...")
101108
return self.state.error

functions/basic_commands.py

+5-30
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,7 @@ def __init__(self, state):
1919
def wait(self, duration):
2020
"""Pauses execution for a certain number of milliseconds."""
2121

22-
verbosity_level = {
23-
1: lambda: print("`wait` called"),
24-
2: lambda: print(f"Waiting for {duration} milliseconds...")
25-
}
26-
27-
verbosity_level[self.broker.state.verbosity]()
22+
self.broker.state.print_status("wait()", description=f"Waiting for {duration} milliseconds...")
2823

2924
wait_message = {
3025
"kind": "rpc_request",
@@ -46,12 +41,7 @@ def wait(self, duration):
4641
def e_stop(self):
4742
"""Emergency locks (E-stops) the Farmduino microcontroller."""
4843

49-
verbosity_level = {
50-
1: lambda: print("`e_stop` called"),
51-
2: lambda: print(f"Triggered device emergency stop at: {datetime.now()}")
52-
}
53-
54-
verbosity_level[self.broker.state.verbosity]()
44+
self.broker.state.print_status("e_stop()", description=f"Triggered device emergency stop at: {datetime.now()}")
5545

5646
stop_message = {
5747
"kind": "rpc_request",
@@ -71,12 +61,7 @@ def e_stop(self):
7161
def unlock(self):
7262
"""Unlocks a locked (E-stopped) device."""
7363

74-
verbosity_level = {
75-
1: lambda: print("`unlock` called"),
76-
2: lambda: print(f"Triggered device unlock at: {datetime.now()}")
77-
}
78-
79-
verbosity_level[self.broker.state.verbosity]()
64+
self.broker.state.print_status("unlock()", description=f"Triggered device unlock at: {datetime.now()}")
8065

8166
unlock_message = {
8267
"kind": "rpc_request",
@@ -96,12 +81,7 @@ def unlock(self):
9681
def reboot(self):
9782
"""Reboots the FarmBot OS and reinitializes the device."""
9883

99-
verbosity_level = {
100-
1: lambda: print("`reboot` called"),
101-
2: lambda: print(f"Triggered device reboot at: {datetime.now()}")
102-
}
103-
104-
verbosity_level[self.broker.state.verbosity]()
84+
self.broker.state.print_status("reboot()", description=f"Triggered device reboot at: {datetime.now()}")
10585

10686
reboot_message = {
10787
**RPC_REQUEST,
@@ -119,12 +99,7 @@ def reboot(self):
11999
def shutdown(self):
120100
"""Shuts down the FarmBot OS and turns the device off."""
121101

122-
verbosity_level = {
123-
1: lambda: print("`shutdown` called"),
124-
2: lambda: print(f"Triggered device shutdown at: {datetime.now()}")
125-
}
126-
127-
verbosity_level[self.broker.state.verbosity]()
102+
self.broker.state.print_status("shutdown()", description=f"Triggered device shutdown at: {datetime.now()}")
128103

129104
shutdown_message = {
130105
**RPC_REQUEST,

functions/broker.py

+13-3
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ def connect(self):
3434
)
3535

3636
self.client.loop_start()
37+
38+
if self.client is None:
39+
self.state.print_status("connect()", description="There was an error connecting to the message broker...")
40+
else:
41+
self.state.print_status("request()", description="Connected to message broker.")
3742

3843
def disconnect(self):
3944
"""Disconnect from the message broker."""
@@ -42,6 +47,9 @@ def disconnect(self):
4247
self.client.loop_stop()
4348
self.client.disconnect()
4449

50+
if self.client is None:
51+
self.state.print_status("disoconnect()", description="Disconnected from message broker.")
52+
4553
return
4654

4755
def publish(self, message):
@@ -58,15 +66,15 @@ def on_connect(self, _client, _userdata, _flags, _rc, channel):
5866

5967
self.client.subscribe(
6068
f"bot/{self.state.token['token']['unencoded']['bot']}/{channel}")
69+
70+
self.state.print_status("on_connect()", description=f"Connected to message broker channel {channel}")
6171

6272
def on_message(self, _client, _userdata, msg):
6373
"""Callback function when message received from message broker."""
6474

6575
self.state.last_message = json.loads(msg.payload)
6676

67-
# print('-' * 100)
68-
# print(f'{msg.topic} ({datetime.now().strftime("%Y-%m-%d %H:%M:%S")})\n')
69-
# print(json.dumps(json.loads(msg.payload), indent=4))
77+
self.state.print_status("on_message()", endpoint_json=json.loads(msg.payload), description=f"TOPIC: {msg.topic} ({datetime.now().strftime('%Y-%m-%d %H:%M:%S')})\n")
7078

7179
def start_listen(self, channel="#"):
7280
"""Establish persistent subscription to message broker channels."""
@@ -79,11 +87,13 @@ def start_listen(self, channel="#"):
7987
self.client.on_message = self.on_message
8088

8189
self.client.loop_start()
90+
self.state.print_status("start_listen()", description=f"Now listening to message broker channel {channel}.")
8291

8392
def stop_listen(self):
8493
"""End subscription to all message broker channels."""
8594

8695
self.client.loop_stop()
8796
self.client.disconnect()
8897

98+
self.state.print_status("stop_listen()", description="Stopped listening to all message broker channels.")
8999
return

functions/camera.py

+2-12
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,7 @@ def __init__(self, state):
1717
def calibrate_camera(self):
1818
"""Performs camera calibration. This action will reset camera calibration settings."""
1919

20-
verbosity_level = {
21-
1: lambda: print("`calibrate_camera` called"),
22-
2: lambda: print(f"Triggered camera calibration at: {datetime.now()}")
23-
}
24-
25-
verbosity_level[self.broker.state.verbosity]()
20+
self.broker.state.print_status("calibrate_camera()", description=f"Triggered camera calibration at: {datetime.now()}")
2621

2722
calibrate_message = {
2823
**RPC_REQUEST,
@@ -40,12 +35,7 @@ def calibrate_camera(self):
4035
def take_photo(self):
4136
"""Takes photo using the device camera and uploads it to the web app."""
4237

43-
verbosity_level = {
44-
1: lambda: print("`take_photo` called"),
45-
2: lambda: print(f"Took a photo at: {datetime.now()}")
46-
}
47-
48-
verbosity_level[self.broker.state.verbosity]()
38+
self.broker.state.print_status("take_photo()", description=f"Took a photo at: {datetime.now()}")
4939

5040
photo_message = {
5141
**RPC_REQUEST,

functions/information.py

+28-18
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44

55
# └── functions/information
66
# ├── [API] get_info()
7-
# ├── [API] set_info()
7+
# ├── [API] edit_info()
8+
# ├── [API] add_info()
89
# ├── [API] safe_z()
910
# ├── [API] garden_size()
1011
# ├── [API] group()
@@ -25,33 +26,37 @@ def __init__(self, state):
2526
def get_info(self, endpoint, id=None):
2627
"""Get information about a specific endpoint."""
2728

28-
endpoint_data = self.auth.request('GET', endpoint, id)
29+
endpoint_data = self.auth.request("GET", endpoint, id)
2930

30-
verbosity_level = {
31-
1: lambda: print("`get_info` called"),
32-
2: lambda: print(json.dumps(endpoint_data, indent=4))
33-
}
31+
self.broker.state.print_status("get_info()", endpoint_json=endpoint_data)
32+
return endpoint_data
33+
34+
def edit_info(self, endpoint, new_data, id=None):
35+
"""Change information contained within an endpoint."""
3436

35-
verbosity_level[self.auth.state.verbosity]()
37+
self.auth.request("PATCH", endpoint, database_id=id, payload=new_data)
38+
endpoint_data = self.get_info(endpoint, id)
3639

40+
self.broker.state.print_status("edit_info()", endpoint_json=endpoint_data)
3741
return endpoint_data
3842

39-
def set_info(self, endpoint, field, value, id=None):
40-
"""Change information contained within an endpoint."""
43+
def add_info(self, endpoint, new_data):
44+
"""Create new information contained within an endpoint."""
4145

42-
new_value = {
43-
field: value
44-
}
46+
self.auth.request("POST", endpoint, database_id=None, payload=new_data)
4547

46-
self.auth.request('PATCH', endpoint, id, new_value)
47-
return self.get_info(endpoint, id)
48+
endpoint_data = self.get_info(endpoint, id=None)
49+
50+
self.broker.state.print_status("add_info()", endpoint_json=endpoint_data)
51+
return endpoint_data
4852

4953
def safe_z(self):
5054
"""Returns the highest safe point along the z-axis."""
5155

5256
config_data = self.get_info('fbos_config')
5357
z_value = config_data["safe_height"]
5458

59+
self.broker.state.print_status("safe_z()", description=f"Safe z={z_value}")
5560
return z_value
5661

5762
def garden_size(self):
@@ -69,6 +74,7 @@ def garden_size(self):
6974
length_y = y_steps / y_mm
7075
area = length_x * length_y
7176

77+
self.broker.state.print_status("garden_size()", description=f"X-axis length={length_x}\n Y-axis length={length_y}\n Area={area}")
7278
return length_x, length_y, area
7379

7480
def group(self, id=None):
@@ -79,6 +85,7 @@ def group(self, id=None):
7985
else:
8086
group_data = self.get_info('point_groups', id)
8187

88+
self.broker.state.print_status("group()", endpoint_json=group_data)
8289
return group_data
8390

8491
def curve(self, id=None):
@@ -89,6 +96,7 @@ def curve(self, id=None):
8996
else:
9097
curve_data = self.get_info('curves', id)
9198

99+
self.broker.state.print_status("curve()", endpoint_json=curve_data)
92100
return curve_data
93101

94102
def soil_height(self):
@@ -105,11 +113,12 @@ def soil_height(self):
105113
}
106114

107115
self.broker.publish(soil_height_message)
108-
return # TODO: return soil height as value
116+
return # TODO: return soil height as value(?)
109117

110118
def read_status(self):
111119
"""Returns the FarmBot status tree."""
112120

121+
self.broker.start_listen("status")
113122
status_message = {
114123
"kind": "rpc_request",
115124
"args": {
@@ -123,11 +132,12 @@ def read_status(self):
123132
}
124133
self.broker.publish(status_message)
125134

126-
self.broker.start_listen("status")
127-
time.sleep(5)
135+
time.sleep(15)
128136
self.broker.stop_listen()
129137

130138
status_tree = self.broker.state.last_message
139+
140+
self.broker.state.print_status("read_status()", endpoint_json=status_tree)
131141
return status_tree
132142

133143
def read_sensor(self, id):
@@ -155,4 +165,4 @@ def read_sensor(self, id):
155165
}
156166

157167
self.broker.publish(sensor_message)
158-
return # TODO
168+
return # TODO return sensor output(?)

0 commit comments

Comments
 (0)