stianaske / pybotvac

Python module for interacting with Neato Botvac Connected vacuum robots.
MIT License
84 stars 44 forks source link

UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 10: ordinal not in range(128) #29

Open ghost opened 5 years ago

ghost commented 5 years ago

Long story short, one of my relatives got a Neato rob and I quickly searched the web to see if it was remotely usable. I found your repo and since I'm currently experimenting with PyQt4, I decided to write a very basic UI for controlling the robot.

However, things go wrong when I try to initialize the robot.

PyQt code (important bits)

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'botvac.ui'
#
# Created by: PyQt4 UI code generator 4.12.1
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
from pybotvac import Robot

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s

try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig)

[
.
.
.
]

        robot = Robot('[REDACTED]','[REDACTED]',u'maps','[REDACTED]')
        def __start(self):
            robot.start_cleaning()

        def __stop(self):
            robot.stop_cleaning()

        def __return(self):
            robot.send_to_base()

        self.startButton.clicked.connect(__start)
        self.stopButton.clicked.connect(__stop)
        self.returnButton.clicked.connect(__return)

Console output

Traceback (most recent call last):
  File "botvac.py", line 161, in <module>
    ui.setupUi(MainWindow)
  File "botvac.py", line 110, in setupUi
    robot = Robot('[REDACTED]','[REDACTED]',u'maps','[REDACTED]')
  File "/home/lili/.local/lib/python2.7/site-packages/pybotvac/robot.py", line 41, in __init__
    if self.service_version not in SUPPORTED_SERVICES:
  File "/home/lili/.local/lib/python2.7/site-packages/pybotvac/robot.py", line 213, in service_version
    return self.available_services['houseCleaning']
  File "/home/lili/.local/lib/python2.7/site-packages/pybotvac/robot.py", line 209, in available_services
    return self.state['availableServices']
  File "/home/lili/.local/lib/python2.7/site-packages/pybotvac/robot.py", line 205, in state
    return self.get_robot_state().json()
  File "/home/lili/.local/lib/python2.7/site-packages/pybotvac/robot.py", line 163, in get_robot_state
    return self._message({'reqId': "1", 'cmd': "getRobotState"})
  File "/home/lili/.local/lib/python2.7/site-packages/pybotvac/robot.py", line 59, in _message
    headers=self._headers)
  File "/usr/lib/python2.7/dist-packages/requests/api.py", line 112, in post
    return request('post', url, data=data, json=json, **kwargs)
  File "/usr/lib/python2.7/dist-packages/requests/api.py", line 58, in request
    return session.request(method=method, url=url, **kwargs)
  File "/usr/lib/python2.7/dist-packages/requests/sessions.py", line 506, in request
    prep = self.prepare_request(req)
  File "/usr/lib/python2.7/dist-packages/requests/sessions.py", line 449, in prepare_request
    hooks=merge_hooks(request.hooks, self.hooks),
  File "/usr/lib/python2.7/dist-packages/requests/models.py", line 309, in prepare
    self.prepare_auth(auth, url)
  File "/usr/lib/python2.7/dist-packages/requests/models.py", line 540, in prepare_auth
    r = auth(self)
  File "/home/lili/.local/lib/python2.7/site-packages/pybotvac/robot.py", line 228, in __call__
    msg = '\n'.join([self.serial.lower(), date, request.body.decode('utf8')])
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 10: ordinal not in range(128)

Temporary fix

I found this answer on StackOverflow, but I feel it is bad practice and kind of hackish.

ghost commented 5 years ago

I already found a quick dirty workaround for executing the robot's command : separating each of them in single file and call them in a subprocess, like this :

from subprocess import call as run
[
.
.
.
]
def __start(self):
  run(["python","startCleaning.py"])

But I think it's not very convenient.