[ Arduino ] 使用 PyBluez對 Arduino發送訊息

第一次學寫 Arduino,先試個水溫使用 Pybluez對 Arduino發送訊息。

Arduino的部分
#include <liquidcrystal.h>
#include <softwareserial.h>

LiquidCrystal lcd(12,11,5,4,3,2);
SoftwareSerial BT(9, 10);

void setup() {
  lcd.begin(16,2);
  BT.begin(9600);
  BT.setTimeout(10);
  
  lcd.print("Hello, world!");
}

void loop() {
  if (BT.available())  // if text arrived in from BT serial...
  {
    String cod=(BT.readString());
    lcd.setCursor(0,0);  // choose first line of LCD
    lcd.print(cod);
  }
}

安裝 PyBluez
安裝前請先參閱各平台的 Requirement

Windows或 Linux應該是可以直接安裝
$ pip install pybluez
我使用的是 MacOS,但 Python的 Bluetooth packages中似乎對 MacOS沒有很好的支援,甚至無法直接使用 pip安裝。
不過 GitHub上都沒有提出這類 issues,有可能我是個案 :P
$ pip install git+https://github.com/pybluez/pybluez.git
安裝後會在 packages中找到 lightblue資料夾,當中會有一個檔案 _bluetoothsockets.py。
class _BluetoothSocket(object):
    ...

    def send(self, data, flags=0):
        # if not isinstance(data, str):
        #     raise TypeError("data must be string, was %s" % type(data))
        if self.__commstate in (SHUT_WR, SHUT_RDWR):
            raise _socket.error(errno.EPIPE, os.strerror(errno.EPIPE))
        self.__checkconnected()

        ...
直接把 5, 6行註解掉(非實際行數),修改後才能正常傳輸數據。
為了顯示 device的名稱還需到 bluetooth資料夾中,找到 macos.py。
def discover_devices(duration=8, flush_cache=True, lookup_names=False,
        lookup_class=False, device_id=-1):
    ...

    # Use lightblue to discover devices on OSX.
    # devices = lightblue.finddevices(getnames=lookup_names, length=duration)
    devices = lightblue.finddevices(getnames=False, length=duration)

    ret = list()
    for device in devices:
        
        ...
直接把 6行 lookup_names修改為 False(非實際行數),如 7行。修改後就能正常使用 lookup_names。
懶得修改的話可以直些使用我小改後的代碼。
$ pip install git+https://hardliver@bitbucket.org/hardliver/pybluez.git

尋找 Bluetooth設備
>>> import bluetooth
>>> 
>>> bluetooth.discover_devices(lookup_names=True)
[(b'12:34:56:78:90:XX', 'HC-05')]
>>> 

接著就試著發送看看吧。
import bluetooth


mac = '12:34:56:78:90:XX'
port = 1
sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
sock.connect((mac,port))

sock.send('Good Luck!'.ljust(16).encode())  # MacOS需使用 bytes type
# sock.send('Good Luck!'.ljust(16))           # Windows和 Linux應該可以直接發送

sock.close()
我使用的液晶顯示器是 16x2,Arduino收到數據後,顯示器並不會把螢幕清空再放上剛收到的數據,而是直接覆蓋。
新數據若沒有比之前長,未被覆蓋的部分就會被保留。
所以使用 ljust(16)指令把空缺補滿到 16格,覆蓋剩餘的部分。

有時候安裝會少安裝 LightAquaBlue.framework這部分,導致無法 import bluetooth。
重試幾次不行就 clone下來安裝吧。

留言