Coverage for farmbot_sidecar_starter_pack/functions/information.py: 100%
109 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-09-04 17:38 -0700
« prev ^ index » next coverage.py v7.4.4, created at 2024-09-04 17:38 -0700
1"""
2Information class.
3"""
5# └── functions/information
6# ├── [API] api_get()
7# ├── [API] api_patch()
8# ├── [API] api_post()
9# ├── [API] api_delete()
10# ├── [API] safe_z()
11# ├── [API] garden_size()
12# ├── [API] group()
13# ├── [API] curve()
14# ├── [BROKER] measure_soil_height()
15# ├── [BROKER] read_status()
16# ├── [BROKER] read_pin()
17# └── [BROKER] read_sensor()
19from .broker import BrokerConnect
20from .api import ApiConnect
22class Information():
23 """Information class."""
24 def __init__(self, state):
25 self.broker = BrokerConnect(state)
26 self.api = ApiConnect(state)
27 self.state = state
29 def api_get(self, endpoint, database_id=None, data_print=True):
30 """Get information about a specific endpoint."""
31 self.state.print_status(description=f"Retrieving {endpoint} information.")
33 endpoint_data = self.api.request("GET", endpoint, database_id)
35 if data_print:
36 self.state.print_status(update_only=True, endpoint_json=endpoint_data)
37 else:
38 self.state.print_status(update_only=True, description=f"Fetched {len(endpoint_data)} items.")
40 return endpoint_data
42 def api_patch(self, endpoint, new_data, database_id=None):
43 """Change information contained within an endpoint."""
44 self.state.print_status(description=f"Editing {endpoint}.")
46 result = self.api.request("PATCH", endpoint, database_id=database_id, payload=new_data)
48 self.state.print_status(update_only=True, endpoint_json=result)
50 return result
52 def api_post(self, endpoint, new_data):
53 """Create new information contained within an endpoint."""
54 self.state.print_status(description=f"Adding new data to {endpoint}.")
56 result = self.api.request("POST", endpoint, database_id=None, payload=new_data)
58 self.state.print_status(update_only=True, endpoint_json=result)
60 return result
62 def api_delete(self, endpoint, database_id=None):
63 """Delete information contained within an endpoint."""
64 self.state.print_status(description=f"Deleting {endpoint} with id={database_id}.")
66 result = self.api.request("DELETE", endpoint, database_id=database_id)
68 self.state.print_status(update_only=True, endpoint_json=result)
70 return result
72 def safe_z(self):
73 """Returns the highest safe point along the z-axis."""
74 self.state.print_status(description="Retrieving safe z value...")
76 config_data = self.api_get('fbos_config')
77 z_value = config_data["safe_height"]
79 self.state.print_status(description=f"Safe z={z_value}", update_only=True)
80 return z_value
82 def garden_size(self):
83 """Return size of garden bed."""
84 self.state.print_status(description="Retrieving garden size...")
86 json_data = self.api_get('firmware_config')
88 x_steps = json_data['movement_axis_nr_steps_x']
89 x_mm = json_data['movement_step_per_mm_x']
91 y_steps = json_data['movement_axis_nr_steps_y']
92 y_mm = json_data['movement_step_per_mm_y']
94 z_steps = json_data['movement_axis_nr_steps_z']
95 z_mm = json_data['movement_step_per_mm_z']
97 garden_size = {
98 "x": x_steps / x_mm,
99 "y": y_steps / y_mm,
100 "z": z_steps / z_mm,
101 }
103 self.state.print_status(endpoint_json=garden_size, update_only=True)
104 return garden_size
106 def group(self, group_id=None):
107 """Returns all group info or single by id."""
108 self.state.print_status(description="Retrieving group information...")
110 if group_id is None:
111 group_data = self.api_get("point_groups")
112 else:
113 group_data = self.api_get('point_groups', group_id)
115 self.state.print_status(endpoint_json=group_data, update_only=True)
116 return group_data
118 def curve(self, curve_id=None):
119 """Returns all curve info or single by id."""
120 self.state.print_status(description="Retrieving curve information...")
122 if curve_id is None:
123 curve_data = self.api_get("curves")
124 else:
125 curve_data = self.api_get('curves', curve_id)
127 self.state.print_status(endpoint_json=curve_data, update_only=True)
128 return curve_data
130 def measure_soil_height(self):
131 """Use the camera to measure the soil height at the current location."""
132 self.state.print_status(description="Measuring soil height...")
134 measure_soil_height_message = {
135 "kind": "execute_script",
136 "args": {
137 "label": "Measure Soil Height"
138 }
139 }
141 self.broker.publish(measure_soil_height_message)
143 def read_status(self):
144 """Returns the FarmBot status tree."""
145 self.state.print_status(description="Reading status...")
146 status_message = {
147 "kind": "read_status",
148 "args": {}
149 }
150 self.broker.publish(status_message)
152 status_trees = self.state.last_messages.get("status", [])
153 status_tree = None if len(status_trees) == 0 else status_trees[-1]
155 self.state.print_status(update_only=True, endpoint_json=status_tree)
156 return status_tree
158 @staticmethod
159 def convert_mode_to_string(mode):
160 """Converts mode to string."""
161 return "digital" if mode == 0 else "analog"
163 def read_pin(self, pin_number, mode=0):
164 """Reads the given pin by number."""
165 mode_str = self.convert_mode_to_string(mode)
166 self.state.print_status(description=f"Reading pin {pin_number} ({mode_str})...")
167 read_pin_message = {
168 "kind": "read_pin",
169 "args": {
170 "pin_number": pin_number,
171 "label": "---",
172 "pin_mode": mode,
173 }
174 }
175 self.broker.publish(read_pin_message)
177 def read_sensor(self, sensor_name):
178 """Reads the given sensor."""
179 self.state.print_status(description=f"Reading {sensor_name} sensor...")
180 sensor = self.get_resource_by_name("sensors", sensor_name)
181 if sensor is None:
182 return
183 sensor_id = sensor["id"]
184 mode = sensor["mode"]
186 sensor_message = {
187 "kind": "read_pin",
188 "args": {
189 "pin_mode": mode,
190 "label": "---",
191 "pin_number": {
192 "kind": "named_pin",
193 "args": {
194 "pin_type": "Sensor",
195 "pin_id": sensor_id,
196 }
197 }
198 }
199 }
201 self.broker.publish(sensor_message)
203 def get_resource_by_name(self, endpoint, resource_name, name_key="label", query=None):
204 """Find a resource by name."""
205 self.state.print_status(description=f"Searching for {resource_name} in {endpoint}.")
206 resources = self.state.fetch_cache(endpoint)
207 if resources is None:
208 resources = self.api_get(endpoint, data_print=False)
209 else:
210 self.state.print_status(description=f"Using {len(resources)} cached items.")
211 if query is not None:
212 for key, value in query.items():
213 resources = [resource for resource in resources if resource[key] == value]
214 resource_names = [resource[name_key] for resource in resources]
215 if resource_name not in resource_names:
216 error = f"ERROR: '{resource_name}' not in {endpoint}: {resource_names}."
217 self.state.print_status(description=error, update_only=True)
218 self.state.error = error
219 self.state.clear_cache(endpoint)
220 return None
222 self.state.save_cache(endpoint, resources)
223 resource = [p for p in resources if p[name_key] == resource_name][0]
224 return resource