Coverage for farmbot_sidecar_starter_pack/functions/information.py: 100%
96 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-08-30 13:00 -0700
« prev ^ index » next coverage.py v7.4.4, created at 2024-08-30 13:00 -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_sensor()
18from .broker import BrokerConnect
19from .api import ApiConnect
21class Information():
22 """Information class."""
23 def __init__(self, state):
24 self.broker = BrokerConnect(state)
25 self.api = ApiConnect(state)
26 self.state = state
28 def api_get(self, endpoint, database_id=None, data_print=True):
29 """Get information about a specific endpoint."""
30 self.state.print_status(description=f"Retrieving {endpoint} information.")
32 endpoint_data = self.api.request("GET", endpoint, database_id)
34 if data_print:
35 self.state.print_status(update_only=True, endpoint_json=endpoint_data)
36 else:
37 self.state.print_status(update_only=True, description=f"Fetched {len(endpoint_data)} items.")
39 return endpoint_data
41 def api_patch(self, endpoint, new_data, database_id=None):
42 """Change information contained within an endpoint."""
43 self.state.print_status(description=f"Editing {endpoint}.")
45 result = self.api.request("PATCH", endpoint, database_id=database_id, payload=new_data)
47 self.state.print_status(update_only=True, endpoint_json=result)
49 return result
51 def api_post(self, endpoint, new_data):
52 """Create new information contained within an endpoint."""
53 self.state.print_status(description=f"Adding new data to {endpoint}.")
55 result = self.api.request("POST", endpoint, database_id=None, payload=new_data)
57 self.state.print_status(update_only=True, endpoint_json=result)
59 return result
61 def api_delete(self, endpoint, database_id=None):
62 """Delete information contained within an endpoint."""
63 self.state.print_status(description=f"Deleting {endpoint} with id={database_id}.")
65 result = self.api.request("DELETE", endpoint, database_id=database_id)
67 self.state.print_status(update_only=True, endpoint_json=result)
69 return result
71 def safe_z(self):
72 """Returns the highest safe point along the z-axis."""
73 self.state.print_status(description="Retrieving safe z value...")
75 config_data = self.api_get('fbos_config')
76 z_value = config_data["safe_height"]
78 self.state.print_status(description=f"Safe z={z_value}", update_only=True)
79 return z_value
81 def garden_size(self):
82 """Return size of garden bed."""
83 self.state.print_status(description="Retrieving garden size...")
85 json_data = self.api_get('firmware_config')
87 x_steps = json_data['movement_axis_nr_steps_x']
88 x_mm = json_data['movement_step_per_mm_x']
90 y_steps = json_data['movement_axis_nr_steps_y']
91 y_mm = json_data['movement_step_per_mm_y']
93 z_steps = json_data['movement_axis_nr_steps_z']
94 z_mm = json_data['movement_step_per_mm_z']
96 garden_size = {
97 "x": x_steps / x_mm,
98 "y": y_steps / y_mm,
99 "z": z_steps / z_mm,
100 }
102 self.state.print_status(endpoint_json=garden_size, update_only=True)
103 return garden_size
105 def group(self, group_id=None):
106 """Returns all group info or single by id."""
107 self.state.print_status(description="Retrieving group information...")
109 if group_id is None:
110 group_data = self.api_get("point_groups")
111 else:
112 group_data = self.api_get('point_groups', group_id)
114 self.state.print_status(endpoint_json=group_data, update_only=True)
115 return group_data
117 def curve(self, curve_id=None):
118 """Returns all curve info or single by id."""
119 self.state.print_status(description="Retrieving curve information...")
121 if curve_id is None:
122 curve_data = self.api_get("curves")
123 else:
124 curve_data = self.api_get('curves', curve_id)
126 self.state.print_status(endpoint_json=curve_data, update_only=True)
127 return curve_data
129 def measure_soil_height(self):
130 """Use the camera to measure the soil height at the current location."""
131 self.state.print_status(description="Measuring soil height...")
133 measure_soil_height_message = {
134 "kind": "execute_script",
135 "args": {
136 "label": "Measure Soil Height"
137 }
138 }
140 self.broker.publish(measure_soil_height_message)
142 def read_status(self):
143 """Returns the FarmBot status tree."""
144 self.state.print_status(description="Reading status...")
145 status_message = {
146 "kind": "read_status",
147 "args": {}
148 }
149 self.broker.publish(status_message)
151 self.broker.listen(self.state.broker_listen_duration, "status")
153 status_tree = self.state.last_messages.get("status")
155 self.state.print_status(update_only=True, endpoint_json=status_tree)
156 return status_tree
158 def read_sensor(self, sensor_name):
159 """Reads the given pin by id."""
160 self.state.print_status(description="Reading sensor...")
161 sensor = self.get_resource_by_name("sensors", sensor_name)
162 if sensor is None:
163 return
164 sensor_id = sensor["id"]
165 mode = sensor["mode"]
167 sensor_message = {
168 "kind": "read_pin",
169 "args": {
170 "pin_mode": mode,
171 "label": "---",
172 "pin_number": {
173 "kind": "named_pin",
174 "args": {
175 "pin_type": "Sensor",
176 "pin_id": sensor_id,
177 }
178 }
179 }
180 }
182 self.broker.publish(sensor_message)
184 def get_resource_by_name(self, endpoint, resource_name, name_key="label", filter=None):
185 """Find a resource by name."""
186 self.state.print_status(description=f"Searching for {resource_name} in {endpoint}.")
187 resources = self.api_get(endpoint, data_print=False)
188 if filter is not None:
189 for key, value in filter.items():
190 resources = [resource for resource in resources if resource[key] == value]
191 resource_names = [resource[name_key] for resource in resources]
192 if resource_name not in resource_names:
193 error = f"ERROR: '{resource_name}' not in {endpoint}: {resource_names}."
194 self.state.print_status(description=error, update_only=True)
195 self.state.error = error
196 return None
198 resource = [p for p in resources if p[name_key] == resource_name][0]
199 return resource