FarmBot / farmbot-mqtt-py

An MQTT wrapper for FarmBot written in Python
MIT License
42 stars 23 forks source link

Reading and updating the tool verification pin value #10

Closed mvilsoet closed 2 years ago

mvilsoet commented 2 years ago

On the web app, clicking “Read Sensor” after mounting a tool should return a pin 63 value of 0. This part works fine. However, when trying to read pin 63 after mounting a tool, the returned value is still 1. After clicking “Read Sensor” on the web app, only then does the code correctly return 0.

How, using python, can I make the exact same effects of the “Read Sensor” button on the web app?

Here’s what I use so far: state[‘pins’][‘63’][‘value’] or bot.state[‘pins’][‘63’][‘value’] both return either 0.0 or 1.0, but don’t update (if a tool is dismounted, it still reads 0.0 until I click the “Read Sensor” button on the web app).

Any help or clarification on how/when these values update would be great! Thanks.

gabrielburnworth commented 2 years ago

That is the correct way to retrieve the state of the pin. To read the pin and update the state, use bot.read_pin(63):

https://github.com/FarmBot/farmbot-py/blob/6a860c9d6277ba88bbc79720e1df4c6482dd57c4/README.md?plain=1#L175


A full example:

from farmbot import Farmbot, FarmbotToken

token = FarmbotToken.download_token("email", "password")
fb = Farmbot(token)
class MyHandler():
    def on_connect(self, bot, mqtt_client):
        bot.read_pin(63)
    def on_change(self, bot, state): pass
    def on_response(self, bot, response): pass
    def on_log(self, bot, log): pass
handler = MyHandler()
fb.connect(handler)

If you ever want to know what commands the web app is sending, you can listen via:

import json
import paho.mqtt.client as mqtt
from farmbot import FarmbotToken

token = FarmbotToken.download_token("email", "password")
token = json.loads(token)['token']

def on_connect(client, userdata, flags, rc):
    client.subscribe(f"bot/{token['unencoded']['bot']}/from_clients")

def on_message(client, userdata, msg):
    print(json.dumps(json.loads(msg.payload), indent=4))

client = mqtt.Client()
client.username_pw_set(
    token['unencoded']['bot'],
    password=token['encoded'])
client.connect(token['unencoded']['mqtt'])
client.on_connect = on_connect
client.on_message = on_message
client.loop_forever()

Where both the web app and the example code above return:

{
    "kind": "rpc_request",
    "args": {
        "label": "6e1fc688-6579-45f7-8e93-0db05d9ebe45",
        "priority": 600
    },
    "body": [
        {
            "kind": "read_pin",
            "args": {
                "pin_number": 63,
                "label": "pin63",
                "pin_mode": 0
            }
        }
    ]
}
mvilsoet commented 2 years ago

Gabriel,

Thank you for your help so far. When we run movement commands, the script you have provided works great, we will use it. However, the problem persists. When we use read_pin(63), the script is reading incorrect(not updated?) values.

For example, it reads:


{
    "kind": "rpc_request",
    "args": {
        "label": "4d74c8ae-ff18-48e8-83bb-3ecc9d400e8d",
        "priority": 600
    },
    "body": [
        {
            "kind": "read_pin",
            "args": {
                "pin_number": 63,
                "label": "pin63",
                "pin_mode": 0
            }
        }
    ]
}

When the Web App button "Read Sensor" returns: 1 (No Tool)

The LOG returned by read_pin(63) is also correct (returns 1, no tool mounted). I think it is not updating the state tree in bot.state['pins']['63']['value']. Any thoughts on this?

gabrielburnworth commented 2 years ago

Here's an example for viewing the pin value over time. Every state update and pin read executed via external script or web app will print the value.

from farmbot import Farmbot, FarmbotToken

token = FarmbotToken.download_token("email", "password")
fb = Farmbot(token)
class MyHandler():
    def on_connect(self, bot, mqtt_client): pass
    def on_change(self, bot, state):
        print(state['pins']['63']['value'])
    def on_response(self, bot, response): pass
    def on_log(self, bot, log): pass
handler = MyHandler()
fb.connect(handler)
mvilsoet commented 2 years ago

I am sorry to bother you once more. However, when I run this given code, the problem is the same.

The tool verification sensor value is updated only when I click the "Read Sensor" button in the Web App. Even after updating in the Web App, the sensor value does not get updated in the state tree. I have provided a screenshot of what I mean.

Screenshot_4

gabrielburnworth commented 2 years ago

{"kind": "read_pin", "args": {"pin_number": 63, "label": "pin63", "pin_mode": 0}} is the command that is sent when bot.read_pin(pin_number=63, pin_mode='digital') is called. pin_mode: 0 corresponds to pin_mode='digital'. The resulting pin value from the read pin command appears in the state tree, which can be viewed via print(state['pins']['63']['value']) and will print as 1.0 or 0.0.

from farmbot import Farmbot, FarmbotToken

token = FarmbotToken.download_token("email", "password")
fb = Farmbot(token)
class MyHandler():
    def on_connect(self, bot, mqtt_client):
        # This is the command request sent:
        bot.read_pin(63)
        print('read pin command sent!')
    def on_change(self, bot, state):
        # This is the resulting value:
        print(f"pin value: {state['pins']['63']['value']}")
    def on_response(self, bot, response): pass
    def on_log(self, bot, log): pass
handler = MyHandler()
fb.connect(handler)
mvilsoet commented 2 years ago

Thank you, that just solved a great deal of issues... So we must read the pin using on_change(), and update the pin wherever we need to in the script. I owe you a drink Gabriel