Coverage for functions/information.py: 100%

96 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-08-30 12:05 -0700

1""" 

2Information class. 

3""" 

4 

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() 

17 

18from .broker import BrokerConnect 

19from .api import ApiConnect 

20 

21class Information(): 

22 """Information class.""" 

23 def __init__(self, state): 

24 self.broker = BrokerConnect(state) 

25 self.api = ApiConnect(state) 

26 self.state = state 

27 

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.") 

31 

32 endpoint_data = self.api.request("GET", endpoint, database_id) 

33 

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.") 

38 

39 return endpoint_data 

40 

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}.") 

44 

45 result = self.api.request("PATCH", endpoint, database_id=database_id, payload=new_data) 

46 

47 self.state.print_status(update_only=True, endpoint_json=result) 

48 

49 return result 

50 

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}.") 

54 

55 result = self.api.request("POST", endpoint, database_id=None, payload=new_data) 

56 

57 self.state.print_status(update_only=True, endpoint_json=result) 

58 

59 return result 

60 

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}.") 

64 

65 result = self.api.request("DELETE", endpoint, database_id=database_id) 

66 

67 self.state.print_status(update_only=True, endpoint_json=result) 

68 

69 return result 

70 

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...") 

74 

75 config_data = self.api_get('fbos_config') 

76 z_value = config_data["safe_height"] 

77 

78 self.state.print_status(description=f"Safe z={z_value}", update_only=True) 

79 return z_value 

80 

81 def garden_size(self): 

82 """Return size of garden bed.""" 

83 self.state.print_status(description="Retrieving garden size...") 

84 

85 json_data = self.api_get('firmware_config') 

86 

87 x_steps = json_data['movement_axis_nr_steps_x'] 

88 x_mm = json_data['movement_step_per_mm_x'] 

89 

90 y_steps = json_data['movement_axis_nr_steps_y'] 

91 y_mm = json_data['movement_step_per_mm_y'] 

92 

93 z_steps = json_data['movement_axis_nr_steps_z'] 

94 z_mm = json_data['movement_step_per_mm_z'] 

95 

96 garden_size = { 

97 "x": x_steps / x_mm, 

98 "y": y_steps / y_mm, 

99 "z": z_steps / z_mm, 

100 } 

101 

102 self.state.print_status(endpoint_json=garden_size, update_only=True) 

103 return garden_size 

104 

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...") 

108 

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) 

113 

114 self.state.print_status(endpoint_json=group_data, update_only=True) 

115 return group_data 

116 

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...") 

120 

121 if curve_id is None: 

122 curve_data = self.api_get("curves") 

123 else: 

124 curve_data = self.api_get('curves', curve_id) 

125 

126 self.state.print_status(endpoint_json=curve_data, update_only=True) 

127 return curve_data 

128 

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...") 

132 

133 measure_soil_height_message = { 

134 "kind": "execute_script", 

135 "args": { 

136 "label": "Measure Soil Height" 

137 } 

138 } 

139 

140 self.broker.publish(measure_soil_height_message) 

141 

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) 

150 

151 self.broker.listen(self.state.broker_listen_duration, "status") 

152 

153 status_tree = self.state.last_messages.get("status") 

154 

155 self.state.print_status(update_only=True, endpoint_json=status_tree) 

156 return status_tree 

157 

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"] 

166 

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 } 

181 

182 self.broker.publish(sensor_message) 

183 

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 

197 

198 resource = [p for p in resources if p[name_key] == resource_name][0] 

199 return resource