class PytomationAPITests(TestCase): def setUp(self): self.api = PytomationAPI() def test_instantiation(self): self.assertIsNotNone(self.api) def test_device_invalid(self): response = self.api.get_response(method='GET', path="junk/test") self.assertEqual(response, 'null') def test_device_list(self): d=StateDevice(name='device_test_1') d.on() response = self.api.get_response(method='GET', path="devices") self.assertTrue('"name": "device_test_1"' in response) def test_device_get(self): d=StateDevice(name='device_test_1') d.on() response = self.api.get_response(method='GET', path="device/" + str(d.type_id)) self.assertTrue('"name": "device_test_1"' in response) def test_device_on(self): d=StateDevice(name='device_test_1') d.off() self.assertEqual(d.state, State.OFF) response = self.api.get_response(method='POST', path="device/" + str(d.type_id), data=['command=on']) self.assertEqual(d.state, State.ON) self.assertTrue('"name": "device_test_1"' in response)
def __init__(self, req, client_addr, server): # self._request = req # self._address = client_addr self._logger = PytoLogging(self.__class__.__name__) self._api = PytomationAPI() self._server = server SimpleHTTPRequestHandler.__init__(self, req, client_addr, server)
class PytomationHandlerClass(SimpleHTTPRequestHandler): def __init__(self, req, client_addr, server): # self._request = req # self._address = client_addr # self._server = server self._logger = PytoLogging(self.__class__.__name__) self._api = PytomationAPI() SimpleHTTPRequestHandler.__init__(self, req, client_addr, server) def translate_path(self, path): global file_path path = file_path + path return path def do_GET(self): self.route() def do_POST(self): self.route() def do_PUT(self): self.route() def do_DELETE(self): self.route() def do_ON(self): self.route() def do_OFF(self): self.route() def route(self): p = self.path.split('/') method = self.command # print "pd:" + self.path + ":" + str(p[1:]) if p[1].lower() == "api": data = None if method.lower() == 'post': length = int(self.headers.getheader('content-length')) data = self.rfile.read(length) # print 'rrrrr' + str(length) + ":" + str(data) self.rfile.close() response = self._api.get_response(method=method, path="/".join(p[2:]), type=None, data=data) self.send_response(200) self.send_header("Content-type", "application/json") self.send_header("Content-length", len(response)) self.end_headers() self.wfile.write(response) self.finish() else: getattr(SimpleHTTPRequestHandler, "do_" + self.command.upper())(self)
class PytoHandlerClass(SimpleHTTPRequestHandler): server = None def __init__(self, req, client_addr, server): # self._request = req # self._address = client_addr self._logger = PytoLogging(self.__class__.__name__) self._api = PytomationAPI() self._server = server SimpleHTTPRequestHandler.__init__(self, req, client_addr, server) def translate_path(self, path): global file_path path = file_path + path return path def do_GET(self): self.route() def do_POST(self): self.route() def do_PUT(self): self.route() def do_DELETE(self): self.route() def do_ON(self): self.route() def do_OFF(self): self.route() def route(self): p = self.path.split("/") method = self.command # print "pd:" + self.path + ":" + str(p[1:]) if p[1].lower() == "api": data = None if method.lower() == "post": length = int(self.headers.getheader("content-length")) data = self.rfile.read(length) # print 'rrrrr' + str(length) + ":" + str(data) + 'fffff' + str(self._server) self.rfile.close() response = self._api.get_response( method=method, path="/".join(p[2:]), type=None, data=data, source=PytoHandlerClass.server ) self.send_response(200) self.send_header("Content-type", "application/json") self.send_header("Content-length", len(response)) self.end_headers() self.wfile.write(response) self.finish() else: getattr(SimpleHTTPRequestHandler, "do_" + self.command.upper())(self)
class PytomationAPITests(TestCase): def setUp(self): self.api = PytomationAPI() def test_instantiation(self): self.assertIsNotNone(self.api) def test_device_invalid(self): response = self.api.get_response(method='GET', path="junk/test") self.assertEqual(response, 'null') def test_device_list(self): d = StateDevice(name='device_test_1') d.on() response = self.api.get_response(method='GET', path="devices") self.assertTrue('"name": "device_test_1"' in response) def test_device_get(self): d = StateDevice(name='device_test_1') d.on() response = self.api.get_response(method='GET', path="device/" + str(d.type_id)) self.assertTrue('"name": "device_test_1"' in response) def test_device_on(self): d = StateDevice(name='device_test_1') d.off() self.assertEqual(d.state, State.OFF) response = self.api.get_response(method='POST', path="device/" + str(d.type_id), data=['command=on']) self.assertEqual(d.state, State.ON) self.assertTrue('"name": "device_test_1"' in response) def test_device_level_encoded(self): d = Light(name='device_test_1') d.off() self.assertEqual(d.state, State.OFF) response = self.api.get_response(method='POST', path="device/" + str(d.type_id), data=['command=level%2C72']) self.assertEqual(d.state, (State.LEVEL, 72)) self.assertTrue('"name": "device_test_1"' in response)
class PytoWebSocketApp(WebSocketApplication): _api = PytomationAPI() def on_open(self): print "WebSocket Client connected" def on_message(self, message): if message: self.ws.send( self._api.get_response(data=message, type=self._api.WEBSOCKET)) def on_close(self, reason): print("WebSocket Client disconnected: ")
class PytoHandlerClass(SimpleHTTPRequestHandler): server = None def __init__(self, req, client_addr, server): # self._request = req # self._address = client_addr self._logger = PytoLogging(self.__class__.__name__) self._api = PytomationAPI() self._server = server SimpleHTTPRequestHandler.__init__(self, req, client_addr, server) def translate_path(self, path): global file_path path = file_path + path return path def authenticate(self): auth = self.headers.get('Authorization') if config.auth_enabled == 'Y' and auth == None: self.do_AUTHHEAD() self.wfile.write('no auth header received'.encode()) return None elif config.auth_enabled != 'Y' or auth in PytomationObject.users: return PytomationObject.users[auth] else: self.do_AUTHHEAD() self.wfile.write(self.headers.getheader('Authorization')) self.wfile.write('Not authenticated'.encode()) self.wfile.write( ('<br />AuthConfig :' + config.auth_enabled).encode()) return None def do_HEAD(self): print("send header") self.send_response(200) self.send_header('Content-type', 'text/html') self.end_headers() def do_AUTHHEAD(self): print("send header") self.send_response(401) self.send_header('WWW-Authenticate', 'Basic realm=\"Pytomation\"') self.send_header('Content-type', 'text/html') self.end_headers() def do_OPTIONS(self): self.send_response(200, "ok") self.send_header('Access-Control-Allow-Origin', '*') if config.auth_enabled == 'Y': self.send_header( 'Access-Control-Allow-Methods', 'GET, POST, OPTIONS, ON, OFF, DELETE, PUT, AUTHHEAD, HEAD') self.send_header("Access-Control-Allow-Headers", "Authorization") else: self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, ON, OFF, DELETE, PUT, HEAD') def do_GET(self): self.route() def do_POST(self): self.route() def do_PUT(self): self.route() def do_DELETE(self): self.route() def do_ON(self): self.route() def do_OFF(self): self.route() def route(self): user = self.authenticate() if not user or self.path == '/api/bridge': return p = self.path.split('/') method = self.command if p[1].lower() == "api": data = None if method.lower() == 'post': length = int(self.headers.get('content-length')) data = self.rfile.read(length) self.rfile.close() response = self._api.get_response(method=method, path="/".join(p[2:]), type=None, data=data, source=PytoHandlerClass.server, user=user) self.send_response(200) self.send_header('Access-Control-Allow-Origin', '*') if config.auth_enabled == 'Y': self.send_header( 'Access-Control-Allow-Methods', 'GET, POST, OPTIONS, ON, OFF, DELETE, PUT, AUTHHEAD, HEAD') self.send_header("Access-Control-Allow-Headers", "Authorization") else: self.send_header( 'Access-Control-Allow-Methods', 'GET, POST, OPTIONS, ON, OFF, DELETE, PUT, HEAD') self.send_header("Content-length", len(response)) self.send_header("Content-type", "application/json") self.end_headers() self.wfile.write(response.encode()) else: getattr(SimpleHTTPRequestHandler, "do_" + self.command.upper())(self)
class PytoHandlerClass(SimpleHTTPRequestHandler): server = None def __init__(self, req, client_addr, server): # self._request = req # self._address = client_addr self._logger = PytoLogging(self.__class__.__name__) self._api = PytomationAPI() self._server = server SimpleHTTPRequestHandler.__init__(self, req, client_addr, server) def translate_path(self, path): global file_path path = file_path + path return path def do_HEAD(self): print "send header" self.send_response(200) self.send_header("Content-type", "text/html") self.end_headers() def do_AUTHHEAD(self): print "send header" self.send_response(401) self.send_header("WWW-Authenticate", 'Basic realm="Test"') self.send_header("Content-type", "text/html") self.end_headers() def do_OPTIONS(self): self.send_response(200, "ok") self.send_header("Access-Control-Allow-Origin", "*") if config.auth_enabled == "Y": self.send_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS, ON, OFF, DELETE, PUT, AUTHHEAD, HEAD") self.send_header("Access-Control-Allow-Headers", "Authorization") else: self.send_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS, ON, OFF, DELETE, PUT, HEAD") def do_GET(self): auth_credentials = base64.b64encode(config.admin_user + ":" + config.admin_password) if config.auth_enabled == "Y" and self.headers.getheader("Authorization") == None: self.do_AUTHHEAD() self.wfile.write("no auth header received") return elif config.auth_enabled != "Y" or self.headers.getheader("Authorization") == "Basic " + auth_credentials: # self.do_HEAD() # self.wfile.write(self.headers.getheader('Authorization')) # self.wfile.write('authenticated!') pass else: self.do_AUTHHEAD() self.wfile.write(self.headers.getheader("Authorization")) self.wfile.write("Not authenticated") self.wfile.write("<br />AuthConfig :" + config.auth_enabled) return self.route() def do_POST(self): self.route() def do_PUT(self): self.route() def do_DELETE(self): self.route() def do_ON(self): self.route() def do_OFF(self): self.route() def route(self): p = self.path.split("/") method = self.command # print "pd:" + self.path + ":" + str(p[1:]) if p[1].lower() == "api": data = None if method.lower() == "post": length = int(self.headers.getheader("content-length")) data = self.rfile.read(length) # print 'rrrrr' + str(length) + ":" + str(data) + 'fffff' + str(self._server) self.rfile.close() response = self._api.get_response( method=method, path="/".join(p[2:]), type=None, data=data, source=PytoHandlerClass.server ) self.send_response(200) self.send_header("Access-Control-Allow-Origin", "*") if config.auth_enabled == "Y": self.send_header( "Access-Control-Allow-Methods", "GET, POST, OPTIONS, ON, OFF, DELETE, PUT, AUTHHEAD, HEAD" ) self.send_header("Access-Control-Allow-Headers", "Authorization") else: self.send_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS, ON, OFF, DELETE, PUT, HEAD") self.send_header("Content-length", len(response)) self.send_header("Content-type", "application/json") self.end_headers() self.wfile.write(response) self.finish() else: getattr(SimpleHTTPRequestHandler, "do_" + self.command.upper())(self)
class PytoWebSocketServer(HAInterface): _api = PytomationAPI() def __init__(self, *args, **kwargs): self._address = kwargs.get('address', config.http_address) self._port = kwargs.get('port', int(config.http_port)) self._path = kwargs.get('path', config.http_path) super(PytoWebSocketServer, self).__init__(self._address, *args, **kwargs) self.unrestricted = True # To override light object restrictions def _init(self, *args, **kwargs): self._ssl_path = None self.ws = None try: self._ssl_path = config.ssl_path except: pass super(PytoWebSocketServer, self)._init(*args, **kwargs) def run(self): resource = collections.OrderedDict() resource['/api/bridge'] = PytoWebSocketApp resource['/api/device*'] = self.api_app resource['/api/voice'] = self.api_app resource['/'] = self.http_file_app if self._ssl_path: self.ws = WebSocketServer((self._address, self._port), Resource(resource), pre_start_hook=auth_hook, keyfile=self._ssl_path + '/server.key', certfile=self._ssl_path + '/server.crt') else: self.ws = WebSocketServer((self._address, self._port), Resource(resource), pre_start_hook=auth_hook) print "Serving WebSocket Connection on", self._address, "port", self._port, "..." StateDevice.onStateChangedGlobal(self.broadcast_state) self.ws.serve_forever() def api_app(self, environ, start_response): method = environ['REQUEST_METHOD'].lower() if method == 'post': data = environ['wsgi.input'].read() else: data = None start_response("200 OK", [("Content-Type", "text/html"), ('Access-Control-Allow-Origin', '*')]) return self._api.get_response(path='/'.join( environ['PATH_INFO'].split('/')[2:]), source=PytoWebSocketServer, method=method, data=data) def http_file_app(self, environ, start_response): path_info = environ['PATH_INFO'] http_file = self._path + path_info if self._ssl_path: protocol = 'https://' else: protocol = 'http://' if os.path.exists(http_file): if os.path.isdir(http_file): if http_file.endswith('/'): http_file += 'index.html' else: if path_info.startswith('/'): location = protocol + self._address + ':' + str( self._port) + path_info + '/' else: location = protocol + self._address + ':' + str( self._port) + '/' + path_info + '/' start_response("302 Found", [("Location", location), ('Access-Control-Allow-Origin', '*')]) return '' mime = mimetypes.guess_type(http_file) start_response("200 OK", [("Content-Type", mime[0]), ('Access-Control-Allow-Origin', '*')]) return open(http_file, "rb") else: start_response("404 Not Found", [("Content-Type", "text/html"), ('Access-Control-Allow-Origin', '*')]) return "404 Not Found" def broadcast_state(self, state, source, prev, device): # TODO: add queue system and separate thread to avoid blocking on long network operations if self.ws: for client in self.ws.clients.values(): message = self._api.get_state_changed_message( state, source, prev, device) client.ws.send(message)
class PytoHandlerClass(SimpleHTTPRequestHandler): server = None def __init__(self, req, client_addr, server): # self._request = req # self._address = client_addr self._logger = PytoLogging(self.__class__.__name__) self._api = PytomationAPI() self._server = server SimpleHTTPRequestHandler.__init__(self, req, client_addr, server) def translate_path(self, path): global file_path path = file_path + path return path def do_HEAD(self): print "send header" self.send_response(200) self.send_header('Content-type', 'text/html') self.end_headers() def do_AUTHHEAD(self): print "send header" self.send_response(401) self.send_header('WWW-Authenticate', 'Basic realm=\"Test\"') self.send_header('Content-type', 'text/html') self.end_headers() def do_GET(self): auth_credentials = base64.b64encode(config.admin_user + ":" + config.admin_password) if self.headers.getheader('Authorization') == None: self.do_AUTHHEAD() self.wfile.write('no auth header received') return elif self.headers.getheader( 'Authorization') == 'Basic ' + auth_credentials: # self.do_HEAD() # self.wfile.write(self.headers.getheader('Authorization')) # self.wfile.write('authenticated!') pass else: self.do_AUTHHEAD() self.wfile.write(self.headers.getheader('Authorization')) self.wfile.write('Not authenticated') return self.route() def do_POST(self): self.route() def do_PUT(self): self.route() def do_DELETE(self): self.route() def do_ON(self): self.route() def do_OFF(self): self.route() def route(self): p = self.path.split('/') method = self.command # print "pd:" + self.path + ":" + str(p[1:]) if p[1].lower() == "api": data = None if method.lower() == 'post': length = int(self.headers.getheader('content-length')) data = self.rfile.read(length) # print 'rrrrr' + str(length) + ":" + str(data) + 'fffff' + str(self._server) self.rfile.close() response = self._api.get_response(method=method, path="/".join(p[2:]), type=None, data=data, source=PytoHandlerClass.server) self.send_response(200) self.send_header("Content-type", "application/json") self.send_header("Content-length", len(response)) self.end_headers() self.wfile.write(response) self.finish() else: getattr(SimpleHTTPRequestHandler, "do_" + self.command.upper())(self)
class PytoHandlerClass(SimpleHTTPRequestHandler): server = None def __init__(self,req, client_addr, server): # self._request = req # self._address = client_addr self._logger = PytoLogging(self.__class__.__name__) self._api = PytomationAPI() self._server = server SimpleHTTPRequestHandler.__init__(self, req, client_addr, server) def translate_path(self, path): global file_path path = file_path + path return path def do_HEAD(self): print "send header" self.send_response(200) self.send_header('Content-type', 'text/html') self.end_headers() def do_AUTHHEAD(self): print "send header" self.send_response(401) self.send_header('WWW-Authenticate', 'Basic realm=\"Test\"') self.send_header('Content-type', 'text/html') self.end_headers() def do_GET(self): auth_credentials = base64.b64encode(config.admin_user + ":" + config.admin_password) if config.auth_enabled == 'Y' and self.headers.getheader('Authorization') == None: self.do_AUTHHEAD() self.wfile.write('no auth header received') return elif config.auth_enabled != 'Y' or self.headers.getheader('Authorization') == 'Basic ' + auth_credentials: # self.do_HEAD() # self.wfile.write(self.headers.getheader('Authorization')) # self.wfile.write('authenticated!') pass else: self.do_AUTHHEAD() self.wfile.write(self.headers.getheader('Authorization')) self.wfile.write('Not authenticated') self.wfile.write('<br />AuthConfig :' + config.auth_enabled) return self.route() def do_POST(self): self.route() def do_PUT(self): self.route() def do_DELETE(self): self.route() def do_ON(self): self.route() def do_OFF(self): self.route() def route(self): p = self.path.split('/') method = self.command # print "pd:" + self.path + ":" + str(p[1:]) if p[1].lower() == "api": data = None if method.lower() == 'post': length = int(self.headers.getheader('content-length')) data = self.rfile.read(length) # print 'rrrrr' + str(length) + ":" + str(data) + 'fffff' + str(self._server) self.rfile.close() response = self._api.get_response(method=method, path="/".join(p[2:]), type=None, data=data, source=PytoHandlerClass.server) self.send_response(200) self.send_header("Content-type", "application/json") self.send_header("Content-length", len(response)) self.end_headers() self.wfile.write(response) self.finish() else: getattr(SimpleHTTPRequestHandler, "do_" + self.command.upper())(self)
def setUp(self): self.api = PytomationAPI()