send command to Puck.JS from the raspberry without Espruino Hub install

Posted on
Page
of 2
/ 2
Next
  • How am i able to send a command from the Raspberry pi to the Puck.js without having to install the hub scripts.
    i.e. connect over bluetooth to the puck.js send command and disconnect or some other nifty efficient way. i would like to send command from rpi to puck.js to send IR signal

    Thanks

  • I haven't used the hub stuff, but will that not work for you?

    To interact with a Puck you fundamentally only need a BLE library in the language you are most familiar with. With that you can connect to and use the pucks built in UART service.

    I think in Node the common one is Noble, but with any library you'd have to write code. I used a BLE library for Go sometime back and added an abstraction layer for Puck commands, including the ability to call functions. It works and might do what you need.

    Another option is of course, Web Bluetooth.

  • any recommendation for python. all i wish to do is to send a command i.e.

    Puck.IR(require("pronto").decode("0000 006D 0000 0082 007D 003F 0010 0010 0010 0010 0010 002F 0010 0010 0010 002F 0010 0010 0010 0010 0010 0010 0010 002F 0010 002F 0010 0010 0010 0010 0010 0010 0010 002F 0010 002F 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 002F 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 002F 0010 0010 0010 0010 0010 0010 0010 0010 0010 002F 0010 002F 0010 002F 0010 002F 0010 002F 0010 002F 0010 002F 0010 002F 0010 0010 0010 0010 0010 002F 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 002F 0010 002F 0010 0010 0010 0010 0010 002F 0010 0010 0010 0010 0010 0010 0010 002F 0010 0010 0010 002F 0010 0010 0010 002F 0010 0010 0010 0010 0010 0010 0010 002F 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 002F 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 002F 0010 0010 0010 0010 0010 0010 0010 002F 0010 0010 0010 002F 0010 0010 0010 0010 0010 002F 0010 0010 0010 003F"));
    
  • what would be the connection speed i need to set up

  • i am trying the following, but i get following error. any help please

    Traceback (most recent call last): File "puck_serial.py", line 6, in

    sock.connect((bd_addr,port))   File "<string>", line 5, in connect bluetooth.btcommon.BluetoothError: (112, 'Host is down')
    
    from bluetooth import *
    import time
    bd_addr = "D8:19:E7:5B:3A:57"
    port = 1
    sock = BluetoothSocket (RFCOMM)
    sock.connect((bd_addr,port))
    print 'waiting'
    while 1:
            data = sock.recv(10)
            print data
            time.sleep(2.0)
            [#tosend](http://forum.espruino.com/sear­ch/?q=%23tosend) = raw_input()
            [#if](http://forum.espruino.com/search/?­q=%23if) tosend != 'q':
            #        sock.send(tosend)
            [#else](http://forum.espruino.com/search­/?q=%23else):
            #        break
    
    sock.close()
    
  • what would be the connection speed i need to set up

    You shouldn't need one at all - connection speed doesn't really apply for something like Bluetooth LE.

    You could look at using bluepy for Python: https://github.com/IanHarvey/bluepy

    However if you're ok with JS then Noble for Node.js is probably one of the most stable BLE libraries out there. You could even use the code that the Espruino CLI tools use as a base: https://github.com/espruino/EspruinoTool­s/blob/gh-pages/core/serial_noble.js

    But at the end of the day you need to:

    • Find and connect to the device
    • Find the service 6e400001b5a3f393e0a9e50e24dcca9e
    • Find the characteristic 6e400002b5a3f393e0a9e50e24dcca9e on that service
    • Write your data to it in chunks of 20 bytes at a time.

    But if you just want an easy time of it, install EspruinoHub and then send an MQTT message containing your JS command to /ble/write/DEVICE_ADDRESS/nus/nus_tx

  • Looks like I posted my reply before I saw your last post.

    In your last post, you're using the bluetooth library. That's for standard Bluetooth (eg. Bluetooth 2), and not Bluetooth LE - so it won't work here.

    You'll need to use bluepy or one of the other Python Bluetooth LE implementations

  • Adafruit have a Python library for their Bluefruit stuff that may work for you: https://github.com/adafruit/Adafruit_Pyt­hon_BluefruitLE/blob/master/examples/low­_level.py

    But basically it looks like there's very little code out there for doing this on Python so you're making your life quite difficult. By contrast there's quite a lot of Node.js stuff.

    This example came up: https://github.com/tigoe/BluetoothLE-Exa­mples/tree/master/noble/readSerial

    Or there's even this library https://www.npmjs.com/package/node-uartb­le

  • Ok, I just created an example for you that should work:

    # based on https://github.com/rlangoy/bluepy_exampl­es_nRF51822_mbed/blob/master/writeLed2.p­y
    import sys
    from bluepy.btle import UUID, Peripheral
    
    if len(sys.argv) != 2:
      print "Fatal, must pass device address:", sys.argv[0], "<device address="">"
      quit()
    
    p = Peripheral(sys.argv[1], "random")
    UartService=p.getServiceByUUID(UUID("6E4­00001-B5A3-F393-E0A9-E50E24DCCA9E"))
    ch = UartService.getCharacteristics(UUID("6E4­00002-B5A3-F393-E0A9-E50E24DCCA9E"))[0]
    # \x03 -> Ctrl-C clears line
    # \x10 -> Echo off for line so don't try and send any text back
    ch.write("\x03\x10LED.toggle()\n");
    p.disconnect()
    

    In your case the text you want to write will be more than 20 characters, so you'll need to write it in 20 character chunks

  • Ok, or code that actually does the splitting for you:

    # based on https://github.com/rlangoy/bluepy_exampl­es_nRF51822_mbed/blob/master/writeLed2.p­y
    import sys
    from bluepy.btle import UUID, Peripheral
    
    if len(sys.argv) != 2:
      print "Fatal, must pass device address:", sys.argv[0], "<device address="">"
      quit()
    
    # \x03 -> Ctrl-C clears line
    # \x10 -> Echo off for line so don't try and send any text back
    # command = "\x03\x10reset()\nLED.toggle()\n"
    command = "\x03\x10clearInterval()\n\x10setInterva­l(function() {LED.toggle()}, 500);\n"
    
    p = Peripheral(sys.argv[1], "random")
    UartService=p.getServiceByUUID(UUID("6E4­00001-B5A3-F393-E0A9-E50E24DCCA9E"))
    ch = UartService.getCharacteristics(UUID("6E4­00002-B5A3-F393-E0A9-E50E24DCCA9E"))[0]
    while len(command)>0: 
      ch.write(command[0:20]);
      command = command[20:];
    p.disconnect()
    
  • Amazing, saved me a heap of testing.

    i get an error with your code

    python puck_serial.py D8:19:E7:5B:3A:57
    
    > Traceback (most recent call last):   File "puck_serial.py", line 13,
    > in <module>
    >     p = Peripheral(sys.argv[1], "random")   File "/usr/local/lib/python2.7/dist-packages/­bluepy/btle.py", line 391, in
    > __init__
    >     self._connect(deviceAddr, addrType, iface)   File "/usr/local/lib/python2.7/dist-packages/­bluepy/btle.py", line 439, in
    > _connect
    >     raise BTLEDisconnectError("Failed to connect to peripheral %s, addr type: %s" % (addr, addrType), rsp)
    > bluepy.btle.BTLEDisconnectError: Failed to connect to peripheral
    > D8:19:E7:5B:3A:57, addr type: random
    
  • i noticed that when i try to run the code above, and then seperatly on another computer try to connect to the puck.js through the web console, that it no longer is found, only when i remove the battery, then i can find it on the web console. maybe the connection from the python code is not negociating properly

  • That's odd - only difference I can see is when I used it, I typed in a lowercase address. Could you try that?

    In https://github.com/rlangoy/bluepy_exampl­es_nRF51822_mbed/blob/master/writeLed2.p­y that I based it on there's a try...finally for disconnection but the exception that's reported is from earlier in the code, so that wouldn't have caused an issue.

    You could also try sudo /etc/init.d/bluetooth restart at the console which should restart the Bluetooth service and would automatically disconnect if it has stayed connected to the device for some reason.

  • the restarting of the bluetooth seems to release the connection, and hence able to find in the web console. but the lower case didn't fix the isse

  • Just a thought - maybe obvious to OP, maybe not. Rather than sending long commands and splitting, could wrap the control commands in functions and send to Puck from IDE and save() to flash. Then just call load() from flash in the control application and call the functions. This would keep the code in the control application manageable. I'm assuming they will all fit in Puck flash which may not be case though?

    If anybody else uses Golang and Puck, this is the library I referred to. Tested on Mac and Raspberry Pi and I've had some joy with it.

  • from debugging, the python script does not go past

    p = Peripheral(sys.argv[1], 'random')

  • Maybe check that you have the latest bluepy and that nothing else is running (eg EspruinoHub) that might be using Bluetooth. And is the Puck's firmware up to date?

    If so, I think your best bet is to post on bluepy's GitHub issue tracker and see they can help figure it out

  • i managed to get the serial working on another RPI, how could i call a function within the puck please

  • Literally just change the python command variable to:

    command = "\x03\x10yourFunctionName();\n"
    

    Apart from the first 2 chars you're just sending JS, so if you want to send arguments it's as easy as "\x03\x10yourFunctionName(1,2,3,'foobar'­);\n"

  • Thanks Gordon,

    i am using the following function on the puck, and ideally i would like to return something back to my python script. i.e temperature value.

    function beam(ircode)
    {
      Puck.IR(require("pronto").decode(ircode)­);
      return "test";
    }
    

    see below my python code as wel. i am so far getting the following value back from the puck, or is it not from the puck hhh

    response value beam(sleep);

    import sys
    from bluepy.btle import UUID, Peripheral
    import time
    import binascii
    
    command = "\x03\x10beam(" +sys.argv[2]+ ");\n"
    p = Peripheral(sys.argv[1], 'random')
    
    try:
            UartService=p.getServiceByUUID(UUID("6E4­00001-B5A3-F393-E0A9-E50E24DCCA9E"))
            ch = UartService.getCharacteristics(UUID("6E4­00002-B5A3-F393-E0A9-E50E24DCCA9E"))[0]
    
            while len(command)>0:
                    ch.write(command[0:20]);
                    command = command[20:];
    
    
    
            time.sleep(1.0) # Allow sensor to stabilise
    
            [#uuidValue](http://forum.espruino.com/s­earch/?q=%23uuidValue)  = btle.UUID("f000aa71-0451-4000-b000-00000­0000000")
            [#lightSensorValue](http://forum.espruin­o.com/search/?q=%23lightSensorValue) = lightService.getCharacteristics(uuidValu­e)[0]
       
            val = ch.read()
            print "response value", val
    
            p.disconnect()
    finally:
            p.disconnect()
    
  • For receive you need the "6E400003-B5A3-F393-E0A9-E50E24DCCA9E" characteristic (there's one for transmit which we're using, and one for receive) - so you may have more luck with rx = UartService.getCharacteristics(UUID("6E4­00003-B5A3-F393-E0A9-E50E24DCCA9E"))[0] and rx.read();.

    However, the best way to get data back from the Puck is to use notifications - but you'll have to find an example of how to do that with bluepy

  • Thanks

    this is such an example, so i need to setup anything on the puck.js side?

    while True:

        if p.waitForNotifications(1.0):
            print("Notification trigger")
            continue
    print("Waiting")
    

    is

    return E.getTemperature();

    sufficient

  • This my code so far on the puck , and I am able to connect using the python code below and send commands, but I am unable to return a value back, actually I do receive something, such as

    <type 'str'>
    <- Serial1
    >
    

    but it should be temperature reading of the puck. any help please

    Puck Code:

    function beam(ircode)
    {
      Puck.IR(require("pronto").decode(ircode)­);
      digitalWrite(LED2,1);
      setTimeout(function() 
      {
        digitalWrite(LED2,0);
      }, delayInMilliseconds);
      return E.getTemperature();
    }
    

    Python:

    import sys
    from bluepy.btle import UUID, Peripheral
    import time
    import binascii
    from bluepy import btle
    
    command = "\x03\x10beam(" +sys.argv[2]+ ");\n"
    
    class MyDelegate(btle.DefaultDelegate):
        def __init__(self):
            btle.DefaultDelegate.__init__(self)
    
        def handleNotification(self, cHandle, data):
            print("A notification was received: %s" %data)
            
    p = Peripheral(sys.argv[1], 'random')
    p.setDelegate(MyDelegate())
    try:
            UartService=p.getServiceByUUID(UUID("6E4­00001-B5A3-F393-E0A9-E50E24DCCA9E"))
            ch = UartService.getCharacteristics(UUID("6E4­00002-B5A3-F393-E0A9-E50E24DCCA9E"))[0]
    
            while len(command)>0:
                    ch.write(command[0:20]);
                    command = command[20:];
    
            
            p.writeCharacteristic(ch.valHandle+1, "\x02\x00")
    
            while True:
                if p.waitForNotifications(1.0):
                    # handleNotification() was called
                    continue
    
                print("Waiting...")
                # Perhaps do something else here
            [#rx](http://forum.espruino.com/search/?­q=%23rx) = UartService.getCharacteristics(UUID("6E4­00003-B5A3-F393-E0A9-E50E24DCCA9E"))[0]
            [#val](http://forum.espruino.com/search/­?q=%23val) = rx.read()
            [#print](http://forum.espruino.com/searc­h/?q=%23print) val
        
    
            p.disconnect()
    finally:
            p.disconnect()
    
  • Looks promising.

    I'd suggest changing command to:

    command = "\x03\x10Bluetooth.println(beam(" +sys.argv[2]+ "));\n"
    

    What's happening is, as mentioned in the code I posted,

    \x10 -> Echo off for line so don't try and send any text back

    If you removed the \x10 from the string in what you wrote, you would see data back, but you'd also see some extra characters (like the code you write echoed back to you, plus a newline and = and then your answer)

    It's much easier to just stop Espruino writing stuff automatically with \x10 and then to explicitly tell it to write stuff with Bluetooth.println

  • i really appreciate your help...
    i have reverted to the hub and mqtt. and can send commands, but how am i able to receive a function response from the puck.

    Many thanks

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

send command to Puck.JS from the raspberry without Espruino Hub install

Posted by Avatar for Ossama @Ossama

Actions