Skip to content

Commit

Permalink
Bookmark
Browse files Browse the repository at this point in the history
  • Loading branch information
Juliana Mashon authored and Juliana Mashon committed Jul 25, 2024
1 parent 5456a47 commit f4b07cf
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 185 deletions.
84 changes: 79 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
# sidecar-starter-pack
Authentication and communication utilities for FarmBot sidecars

## 📖 Contents

* [Installation](#-installation-mac-os)
* [Getting Started](#-getting-started)
* [Functions](#-functions)
* [Setup](#setup)
* [Information](#information)
* [Messaging](#messaging)
* [Basic Commands](#basic-commands)
* [Movement](#movement)
* [Peripherals](#peripherals)
* [Broker Commands](#broker-commands)
* [Developer Info](#-developer-info)
* [api_connect.py](#api_connectpy)
* [broker_connect.py](#broker_connectpy)

## 💻 Installation (Mac OS)
To set up the project locally, follow these steps:

Expand Down Expand Up @@ -33,7 +49,7 @@ python3 -m pip install paho-mqtt
## 🌱 Getting Started
To generate your authorization token and get started:

(1) Import `farmbot_utilities` and create an instance.
(1) Import `main.py` and create an instance.
```
from farmbot_utilities import Farmbot
bot = Farmbot()
Expand Down Expand Up @@ -77,19 +93,77 @@ bot.move(30,40,10)
bot.disconnect_broker()
```

## 🧭 Functions

### Setup

`get_token()` generates user authentication token; call before any other function
`connect_broker()` establishes persistent connect to message broker
`disconnect_broker()` disconnects from the message broker
`listen_broker()` displays messages sent to/from message broker

### Information

`get_info()` returns information about a specific endpoint
`set_info()` edits information belonging to preexisting endpoint
env()
group()
curve()
read_status()
read_sensor()
safe_z()
garden_size()

### Messaging

`log()` sends a new log message via the API
`message()` sends a new log message via the message broker
`debug()` sends a log message of type 'debug' via the message broker
`toast()` sends a log message of type 'toast' via the message broker

### Basic Commands

wait()
e_stop()
unlock()
reboot()
shutdown()

### Movement

move()
set_home()
find_home()
axis_length()

### Peripherals

control_peripheral()
toggle_peripheral()
on()
off()

### Broker Commands

calibrate_camera()
control_servo()
take_photo()
soil_height()
detect_weeds()

## 🧰 Developer Info

### farmbot_API
### api_connect.py
Background: https://developer.farm.bot/v15/docs/web-app/rest-api

Formatting: functions in `farmbot_utilities` which interact with the API require an endpoint, which is truncated onto the HTTP request.
Formatting: functions in `api_functions.py` and `main.py` which interact with the API require an endpoint, which is truncated onto the HTTP request.

List of endpoints: https://developer.farm.bot/v15/docs/web-app/api-docs

> [!CAUTION]
> 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.
### farmbot_BROKER
### broker_connect.py
Background: https://developer.farm.bot/v15/docs/message-broker

Formatting: functions in `farmbot_utilities` which interact with the message broker send a message containing CelerScript. The messages require the pre-formatted `RPC_request` included in `farmbot_utilities` as the first line of the message.
Formatting: functions in `broker_functions.py` and `main.py` which interact with the message broker send a message containing CeleryScript. The messages require the pre-formatted `RPC_request` included in `broker_functions.py` as the first line of the message.
63 changes: 27 additions & 36 deletions api_connect.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,6 @@ def __init__(self):

## ERROR HANDLING

def token_handling(self, response):
"""Handle errors relating to bad user auth token requests."""

# Handle HTTP status codes
if response.status_code == 200:
return 200
elif response.status_code == 404:
self.error = "ERROR: The server address does not exist."
elif response.status_code == 422:
self.error = "ERROR: Incorrect email address or password."
else:
self.error = f"ERROR: Unexpected status code {response.status_code}"

# Handle DNS resolution errors
if response is None:
self.error = "ERROR: There was a problem with the request."
elif isinstance(response, requests.exceptions.ConnectionError):
self.error = "ERROR: The server address does not exist."
elif isinstance(response, requests.exceptions.Timeout):
self.error = "ERROR: The request timed out."
elif isinstance(response, requests.exceptions.RequestException):
self.error = "ERROR: There was a problem with the request."

return 0

def request_handling(self, response):
"""Handle errors relating to bad endpoints and user requests."""

Expand All @@ -54,23 +29,39 @@ def request_handling(self, response):
else:
self.error = json.dumps(f"UNEXPECTED ERROR {response.status_code}: {response.text}", indent=2)

return 0

## FUNCTIONS

def get_token(self, email, password, server):
"""Fetch user authentication token via API."""

headers = {'content-type': 'application/json'}
user = {'user': {'email': email, 'password': password}}
response = requests.post(f'{server}/api/tokens', headers=headers, json=user)
try:
headers = {'content-type': 'application/json'}
user = {'user': {'email': email, 'password': password}}
response = requests.post(f'{server}/api/tokens', headers=headers, json=user)
# Handle HTTP status codes
if response.status_code == 200:
token_data = response.json()
self.error = None
return token_data
elif response.status_code == 404:
self.error = "HTTP ERROR: The server address does not exist."
elif response.status_code == 422:
self.error = "HTTP ERROR: Incorrect email address or password."
else:
self.error = f"HTTP ERROR: Unexpected status code {response.status_code}"
# Handle DNS resolution errors
except requests.exceptions.RequestException as e:
if isinstance(e, requests.exceptions.ConnectionError):
self.error = "DNS ERROR: The server address does not exist."
elif isinstance(e, requests.exceptions.Timeout):
self.error = "DNS ERROR: The request timed out."
elif isinstance(e, requests.exceptions.RequestException):
self.error = "DNS ERROR: There was a problem with the request."
except Exception as e:
self.error = f"DNS ERROR: An unexpected error occurred: {str(e)}"

if self.token_handling(response) == 200:
token_data = response.json()
self.error = None
return token_data
else:
return self.error
self.token = None
return self.error

def check_token(self):
"""Ensure user authentication token has been generated and persists."""
Expand Down
14 changes: 8 additions & 6 deletions api_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@ def __init__(self):
self.echo = True
self.verbose = True

def return_config(self, return_value): # TODO: which functions return json()
def __return_config(self, return_value, json_val=False): # TODO: which functions return json()
"""Configure echo and verbosity of function returns."""

if self.echo is True and self.verbose is True:
print('-' * 100)
print(f'FUNCTION: {return_value}\n')
return print(return_value)
if json_val is True:
print(f'FUNCTION: {return_value}\n')
return print(return_value)
else:
print(f'FUNCTION: {return_value}\n')
return print(return_value)
elif self.echo is True and self.verbose is False:
print('-' * 100)
return print(return_value)
Expand Down Expand Up @@ -42,13 +46,11 @@ def set_info(self, endpoint, field, value, id=None):
self.api_connect.patch(endpoint, id, new_value)
return self.api_connect.get(endpoint, id)

def env(self, id=None, field=None, new_val=None): # TODO: why are there '?'
def env(self, id=None, field=None, new_val=None): # TODO: Fix
if id is None:
data = self.api_connect.get('farmware_envs', id=None)
print(data) # ?
else:
data = self.api_connect.get('farmware_envs', id)
print(data) # ?
# return ...

def log(self, message, type=None, channel=None):
Expand Down
16 changes: 0 additions & 16 deletions broker_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,6 @@ def __init__(self):
self.echo = True
self.verbose = True

def return_config(self, return_value): # TODO: which functions return json()
"""Configure echo and verbosity of function returns."""

if self.echo is True and self.verbose is True:
print('-' * 100)
print(f'FUNCTION: {return_value}\n')
return print(return_value)
elif self.echo is True and self.verbose is False:
print('-' * 100)
return print(return_value)
elif self.echo is False and self.verbose is False:
return return_value
else:
print('-' * 100)
return print("ERROR: Incompatible return configuration.")

## INFORMATION

def read_status(self):
Expand Down
Loading

0 comments on commit f4b07cf

Please sign in to comment.