diff --git a/utils/yunbridge/Makefile b/utils/yunbridge/Makefile new file mode 100644 index 000000000..ae4923252 --- /dev/null +++ b/utils/yunbridge/Makefile @@ -0,0 +1,48 @@ +# +# Copyright (C) 2006-2011 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=yunbridge +PKG_VERSION:=160 + +PKG_RELEASE=$(PKG_SOURCE_VERSION) + +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL:=https://github.com/arduino/YunBridge.git +PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) +PKG_SOURCE_VERSION:=f2042052115e71ad2c91f77e78d21db8275fcdd6 +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz + +PKG_MAINTAINER:=John Crispin +PKG_LICENSE:=GPL-2.0 + +include $(INCLUDE_DIR)/package.mk + +define Package/yunbridge + SECTION:=utils + CATEGORY:=Utilities + TITLE:=Arduino YUN bridge library + URL:=http://arduino.cc/ + DEPENDS:=+python +endef + +define Package/yunbridge/description + Arduino YUN bridge library +endef + +define Build/Compile + true +endef + +define Package/yunbridge/install + mkdir -p $(1)/usr/lib/python2.7/bridge + $(CP) $(PKG_BUILD_DIR)/bridge/*.py $(1)/usr/lib/python2.7/bridge/ + $(CP) ./files/* $(1) +endef + +$(eval $(call BuildPackage,yunbridge)) diff --git a/utils/yunbridge/files/etc/config/yunbridge b/utils/yunbridge/files/etc/config/yunbridge new file mode 100644 index 000000000..fe8dd2891 --- /dev/null +++ b/utils/yunbridge/files/etc/config/yunbridge @@ -0,0 +1,6 @@ +config bridge config + option socket_timeout 5 + option secure_rest_api false + + # remove this line to activae the yunbridge + option disabled 1 diff --git a/utils/yunbridge/files/etc/init.d/yunbridge b/utils/yunbridge/files/etc/init.d/yunbridge new file mode 100755 index 000000000..4b482203e --- /dev/null +++ b/utils/yunbridge/files/etc/init.d/yunbridge @@ -0,0 +1,22 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2013 OpenWrt.org + +# start after and stop before networking +START=20 +STOP=89 + +USE_PROCD=1 + +service_triggers() +{ + procd_add_reload_trigger "yunbridge" +} + +start_service() +{ + [ "$(uci -q get yunbridge.config.disabled)" = "1" ] && return 0 + procd_open_instance + procd_set_param command "/sbin/yunbridge" + procd_set_param respawn + procd_close_instance +} diff --git a/utils/yunbridge/files/sbin/yunbridge b/utils/yunbridge/files/sbin/yunbridge new file mode 100755 index 000000000..c8e4812be --- /dev/null +++ b/utils/yunbridge/files/sbin/yunbridge @@ -0,0 +1,6 @@ +#!/bin/sh +stty -F /dev/ttyS0 2500000 clocal cread cs8 -cstopb -parenb +exec < /dev/ttyS0 +exec > /dev/ttyS0 +exec 2> /dev/ttyS0 +askfirst bin/ash --login diff --git a/utils/yunbridge/files/usr/bin/pretty-wifi-info.lua b/utils/yunbridge/files/usr/bin/pretty-wifi-info.lua new file mode 100755 index 000000000..d91817afa --- /dev/null +++ b/utils/yunbridge/files/usr/bin/pretty-wifi-info.lua @@ -0,0 +1,75 @@ +#!/usr/bin/lua + +local function get_basic_net_info(network, iface, accumulator) + local net = network:get_network(iface) + local device = net and net:get_interface() + + if device then + accumulator["uptime"] = net:uptime() + accumulator["iface"] = device:name() + accumulator["mac"] = device:mac() + accumulator["rx_bytes"] = device:rx_bytes() + accumulator["tx_bytes"] = device:tx_bytes() + accumulator["ipaddrs"] = {} + + for _, ipaddr in ipairs(device:ipaddrs()) do + accumulator.ipaddrs[#accumulator.ipaddrs + 1] = { + addr = ipaddr:host():string(), + netmask = ipaddr:mask():string() + } + end + end +end + +local function get_wifi_info(network, iface, accumulator) + local net = network:get_wifinet(iface) + + if net then + local dev = net:get_device() + if dev then + accumulator["mode"] = net:active_mode() + accumulator["ssid"] = net:active_ssid() + accumulator["encryption"] = net:active_encryption() + accumulator["quality"] = net:signal_percent() + end + end +end + +local function collect_wifi_info() + local network = require"luci.model.network".init() + local accumulator = {} + get_basic_net_info(network, "lan", accumulator) + get_wifi_info(network, "wlan0", accumulator) + return accumulator +end + +local info = collect_wifi_info() + +print("Current WiFi configuration") +if info.ssid then + print("SSID: " .. info.ssid) +end +if info.mode then + print("Mode: " .. info.mode) +end +if info.quality then + print("Signal: " .. info.quality .. "%") +end +if info.encryption then + print("Encryption method: " .. info.encryption) +end +if info.iface then + print("Interface name: " .. info.iface) +end +if info.uptime then + print("Active for: " .. math.floor(info.uptime / 60) .. " minutes") +end +if #info.ipaddrs > 0 then + print("IP address: " .. info.ipaddrs[1].addr .. "/" .. info.ipaddrs[1].netmask) +end +if info.mac then + print("MAC address: " .. info.mac) +end +if info.rx_bytes and info.tx_bytes then + print("RX/TX: " .. math.floor(info.rx_bytes / 1024) .. "/" .. math.floor(info.tx_bytes / 1024) .. " KBs") +end diff --git a/utils/yunbridge/files/usr/lib/lua/luci/controller/arduino/index.lua b/utils/yunbridge/files/usr/lib/lua/luci/controller/arduino/index.lua new file mode 100644 index 000000000..8d3b7eb51 --- /dev/null +++ b/utils/yunbridge/files/usr/lib/lua/luci/controller/arduino/index.lua @@ -0,0 +1,414 @@ +--[[ +This file is part of YunWebUI. + +YunWebUI is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +As a special exception, you may use this file as part of a free software +library without restriction. Specifically, if other files instantiate +templates or use macros or inline functions from this file, or you compile +this file and link it with other files to produce an executable, this +file does not by itself cause the resulting executable to be covered by +the GNU General Public License. This exception does not however +invalidate any other reasons why the executable file might be covered by +the GNU General Public License. + +Copyright 2013 Arduino LLC (http://www.arduino.cc/) +]] + +module("luci.controller.arduino.index", package.seeall) + +local function not_nil_or_empty(value) + return value and value ~= "" +end + +local function get_first(cursor, config, type, option) + return cursor:get_first(config, type, option) +end + +local function set_first(cursor, config, type, option, value) + cursor:foreach(config, type, function(s) + if s[".type"] == type then + cursor:set(config, s[".name"], option, value) + end + end) +end + + +local function to_key_value(s) + local parts = luci.util.split(s, ":") + parts[1] = luci.util.trim(parts[1]) + parts[2] = luci.util.trim(parts[2]) + return parts[1], parts[2] +end + +function http_error(code, text) + luci.http.prepare_content("text/plain") + luci.http.status(code) + if text then + luci.http.write(text) + end +end + +function index() + function luci.dispatcher.authenticator.arduinoauth(validator, accs, default) + require("luci.controller.arduino.index") + + local user = luci.http.formvalue("username") + local pass = luci.http.formvalue("password") + local basic_auth = luci.http.getenv("HTTP_AUTHORIZATION") + + if user and validator(user, pass) then + return user + end + + if basic_auth and basic_auth ~= "" then + local decoded_basic_auth = nixio.bin.b64decode(string.sub(basic_auth, 7)) + user = string.sub(decoded_basic_auth, 0, string.find(decoded_basic_auth, ":") - 1) + pass = string.sub(decoded_basic_auth, string.find(decoded_basic_auth, ":") + 1) + end + + if user then + if #pass ~= 64 and validator(user, pass) then + return user + elseif #pass == 64 then + local uci = luci.model.uci.cursor() + uci:load("yunbridge") + local stored_encrypted_pass = uci:get_first("yunbridge", "bridge", "password") + if pass == stored_encrypted_pass then + return user + end + end + end + + luci.http.header("WWW-Authenticate", "Basic realm=\"yunbridge\"") + luci.http.status(401) + + return false + end + + local function make_entry(path, target, title, order) + local page = entry(path, target, title, order) + page.leaf = true + return page + end + + -- web panel + local webpanel = entry({ "webpanel" }, alias("webpanel", "go_to_homepage"), _("%s Web Panel") % luci.sys.hostname(), 10) + webpanel.sysauth = "root" + webpanel.sysauth_authenticator = "arduinoauth" + + make_entry({ "webpanel", "go_to_homepage" }, call("go_to_homepage"), nil) + + --api security level + local uci = luci.model.uci.cursor() + uci:load("yunbridge") + local secure_rest_api = uci:get_first("yunbridge", "bridge", "secure_rest_api") + local rest_api_sysauth = false + if secure_rest_api == "true" then + rest_api_sysauth = webpanel.sysauth + end + + --storage api + local data_api = node("data") + data_api.sysauth = rest_api_sysauth + data_api.sysauth_authenticator = webpanel.sysauth_authenticator + make_entry({ "data", "get" }, call("storage_send_request"), nil).sysauth = rest_api_sysauth + make_entry({ "data", "put" }, call("storage_send_request"), nil).sysauth = rest_api_sysauth + make_entry({ "data", "delete" }, call("storage_send_request"), nil).sysauth = rest_api_sysauth + local mailbox_api = node("mailbox") + mailbox_api.sysauth = rest_api_sysauth + mailbox_api.sysauth_authenticator = webpanel.sysauth_authenticator + make_entry({ "mailbox" }, call("build_bridge_mailbox_request"), nil).sysauth = rest_api_sysauth + + --plain socket endpoint + local plain_socket_endpoint = make_entry({ "arduino" }, call("board_plain_socket"), nil) + plain_socket_endpoint.sysauth = rest_api_sysauth + plain_socket_endpoint.sysauth_authenticator = webpanel.sysauth_authenticator +end + +function go_to_homepage() + luci.http.redirect("/index.html") +end + +local function build_bridge_request(command, params) + + local bridge_request = { + command = command + } + + if command == "raw" then + params = table.concat(params, "/") + if not_nil_or_empty(params) then + bridge_request["data"] = params + end + return bridge_request + end + + if command == "get" then + if not_nil_or_empty(params[1]) then + bridge_request["key"] = params[1] + end + return bridge_request + end + + if command == "put" and not_nil_or_empty(params[1]) and params[2] then + bridge_request["key"] = params[1] + bridge_request["value"] = params[2] + return bridge_request + end + + if command == "delete" and not_nil_or_empty(params[1]) then + bridge_request["key"] = params[1] + return bridge_request + end + + return nil +end + +local function extract_jsonp_param(query_string) + if not not_nil_or_empty(query_string) then + return nil + end + + local qs_parts = string.split(query_string, "&") + for idx, value in ipairs(qs_parts) do + if string.find(value, "jsonp") == 1 or string.find(value, "callback") == 1 then + return string.sub(value, string.find(value, "=") + 1) + end + end +end + +local function parts_after(url_part) + local url = luci.http.getenv("PATH_INFO") + local url_after_part = string.find(url, "/", string.find(url, url_part) + 1) + if not url_after_part then + return {} + end + return luci.util.split(string.sub(url, url_after_part + 1), "/") +end + +function storage_send_request() + local method = luci.http.getenv("REQUEST_METHOD") + local jsonp_callback = extract_jsonp_param(luci.http.getenv("QUERY_STRING")) + local parts = parts_after("data") + local command = parts[1] + if not command or command == "" then + luci.http.status(404) + return + end + local params = {} + for idx, param in ipairs(parts) do + if idx > 1 and not_nil_or_empty(param) then + table.insert(params, param) + end + end + + -- TODO check method? + local bridge_request = build_bridge_request(command, params) + if not bridge_request then + luci.http.status(403) + return + end + + local uci = luci.model.uci.cursor() + uci:load("yunbridge") + local socket_timeout = uci:get_first("yunbridge", "bridge", "socket_timeout", 5) + + local sock, code, msg = nixio.connect("127.0.0.1", 5700) + if not sock then + code = code or "" + msg = msg or "" + http_error(500, "nil socket, " .. code .. " " .. msg) + return + end + + sock:setopt("socket", "sndtimeo", socket_timeout) + sock:setopt("socket", "rcvtimeo", socket_timeout) + sock:setopt("tcp", "nodelay", 1) + + local json = require("luci.json") + + sock:write(json.encode(bridge_request)) + sock:writeall("\n") + + local response_text = {} + while true do + local bytes = sock:recv(4096) + if bytes and #bytes > 0 then + table.insert(response_text, bytes) + end + + local json_response = json.decode(table.concat(response_text)) + if json_response then + sock:close() + luci.http.status(200) + if jsonp_callback then + luci.http.prepare_content("application/javascript") + luci.http.write(jsonp_callback) + luci.http.write("(") + luci.http.write_json(json_response) + luci.http.write(");") + else + luci.http.prepare_content("application/json") + luci.http.write(json.encode(json_response)) + end + return + end + + if not bytes or #response_text == 0 then + sock:close() + http_error(500, "Empty response") + return + end + end + + sock:close() +end + +function board_plain_socket() + local function send_response(response_text, jsonp_callback) + if not response_text then + luci.http.status(500) + return + end + + local rows = luci.util.split(response_text, "\r\n") + if #rows == 1 or string.find(rows[1], "Status") ~= 1 then + luci.http.prepare_content("text/plain") + luci.http.status(200) + luci.http.write(response_text) + return + end + + local body_start_at_idx = -1 + local content_type = "text/plain" + for idx, row in ipairs(rows) do + if row == "" then + body_start_at_idx = idx + break + end + + local key, value = to_key_value(row) + if string.lower(key) == "status" then + luci.http.status(tonumber(value)) + elseif string.lower(key) == "content-type" then + content_type = value + else + luci.http.header(key, value) + end + end + + local response_body = table.concat(rows, "\r\n", body_start_at_idx + 1) + if content_type == "application/json" and jsonp_callback then + local json = require("luci.json") + luci.http.prepare_content("application/javascript") + luci.http.write(jsonp_callback) + luci.http.write("(") + luci.http.write_json(json.decode(response_body)) + luci.http.write(");") + else + luci.http.prepare_content(content_type) + luci.http.write(response_body) + end + end + + local method = luci.http.getenv("REQUEST_METHOD") + local jsonp_callback = extract_jsonp_param(luci.http.getenv("QUERY_STRING")) + local parts = parts_after("arduino") + local params = {} + for idx, param in ipairs(parts) do + if not_nil_or_empty(param) then + table.insert(params, param) + end + end + + if #params == 0 then + luci.http.status(404) + return + end + + params = table.concat(params, "/") + + local uci = luci.model.uci.cursor() + uci:load("yunbridge") + local socket_timeout = uci:get_first("yunbridge", "bridge", "socket_timeout", 5) + + local sock, code, msg = nixio.connect("127.0.0.1", 5555) + if not sock then + code = code or "" + msg = msg or "" + http_error(500, "Could not connect to YunServer " .. code .. " " .. msg) + return + end + + sock:setopt("socket", "sndtimeo", socket_timeout) + sock:setopt("socket", "rcvtimeo", socket_timeout) + sock:setopt("tcp", "nodelay", 1) + + sock:write(params) + sock:writeall("\r\n") + + local response_text = sock:readall() + sock:close() + + send_response(response_text, jsonp_callback) +end + +function build_bridge_mailbox_request() + local method = luci.http.getenv("REQUEST_METHOD") + local jsonp_callback = extract_jsonp_param(luci.http.getenv("QUERY_STRING")) + local parts = parts_after("mailbox") + local params = {} + for idx, param in ipairs(parts) do + if not_nil_or_empty(param) then + table.insert(params, param) + end + end + + if #params == 0 then + luci.http.status(400) + return + end + + local bridge_request = build_bridge_request("raw", params) + if not bridge_request then + luci.http.status(403) + return + end + + local uci = luci.model.uci.cursor() + uci:load("yunbridge") + local socket_timeout = uci:get_first("yunbridge", "bridge", "socket_timeout", 5) + + local sock, code, msg = nixio.connect("127.0.0.1", 5700) + if not sock then + code = code or "" + msg = msg or "" + http_error(500, "nil socket, " .. code .. " " .. msg) + return + end + + sock:setopt("socket", "sndtimeo", socket_timeout) + sock:setopt("socket", "rcvtimeo", socket_timeout) + sock:setopt("tcp", "nodelay", 1) + + local json = require("luci.json") + + sock:write(json.encode(bridge_request)) + sock:writeall("\n") + sock:close() + + luci.http.status(200) +end diff --git a/utils/yunbridge/files/usr/lib/lua/luci/sha256.lua b/utils/yunbridge/files/usr/lib/lua/luci/sha256.lua new file mode 100644 index 000000000..b5e2dea60 --- /dev/null +++ b/utils/yunbridge/files/usr/lib/lua/luci/sha256.lua @@ -0,0 +1,199 @@ +-- +-- Code merged by gravityscore at http://pastebin.com/gsFrNjbt +-- +-- Adaptation of the Secure Hashing Algorithm (SHA-244/256) +-- Found Here: http://lua-users.org/wiki/SecureHashAlgorithm +-- +-- Using an adapted version of the bit library +-- Found Here: https://bitbucket.org/Boolsheet/bslf/src/1ee664885805/bit.lua +-- + +module("luci.sha256", package.seeall) + +local MOD = 2 ^ 32 +local MODM = MOD - 1 + +local function memoize(f) + local mt = {} + local t = setmetatable({}, mt) + function mt:__index(k) + local v = f(k) + t[k] = v + return v + end + + return t +end + +local function make_bitop_uncached(t, m) + local function bitop(a, b) + local res, p = 0, 1 + while a ~= 0 and b ~= 0 do + local am, bm = a % m, b % m + res = res + t[am][bm] * p + a = (a - am) / m + b = (b - bm) / m + p = p * m + end + res = res + (a + b) * p + return res + end + + return bitop +end + +local function make_bitop(t) + local op1 = make_bitop_uncached(t, 2 ^ 1) + local op2 = memoize(function(a) return memoize(function(b) return op1(a, b) end) end) + return make_bitop_uncached(op2, 2 ^ (t.n or 1)) +end + +local bxor1 = make_bitop({ [0] = { [0] = 0, [1] = 1 }, [1] = { [0] = 1, [1] = 0 }, n = 4 }) + +local function bxor(a, b, c, ...) + local z = nil + if b then + a = a % MOD + b = b % MOD + z = bxor1(a, b) + if c then z = bxor(z, c, ...) end + return z + elseif a then return a % MOD + else return 0 + end +end + +local function band(a, b, c, ...) + local z + if b then + a = a % MOD + b = b % MOD + z = ((a + b) - bxor1(a, b)) / 2 + if c then z = bit32_band(z, c, ...) end + return z + elseif a then return a % MOD + else return MODM + end +end + +local function bnot(x) return (-1 - x) % MOD end + +local function rshift1(a, disp) + if disp < 0 then return lshift(a, -disp) end + return math.floor(a % 2 ^ 32 / 2 ^ disp) +end + +local function rshift(x, disp) + if disp > 31 or disp < -31 then return 0 end + return rshift1(x % MOD, disp) +end + +local function lshift(a, disp) + if disp < 0 then return rshift(a, -disp) end + return (a * 2 ^ disp) % 2 ^ 32 +end + +local function rrotate(x, disp) + x = x % MOD + disp = disp % 32 + local low = band(x, 2 ^ disp - 1) + return rshift(x, disp) + lshift(low, 32 - disp) +end + +local k = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, +} + +local function str2hexa(s) + return (string.gsub(s, ".", function(c) return string.format("%02x", string.byte(c)) end)) +end + +local function num2s(l, n) + local s = "" + for i = 1, n do + local rem = l % 256 + s = string.char(rem) .. s + l = (l - rem) / 256 + end + return s +end + +local function s232num(s, i) + local n = 0 + for i = i, i + 3 do n = n * 256 + string.byte(s, i) end + return n +end + +local function preproc(msg, len) + local extra = 64 - ((len + 9) % 64) + len = num2s(8 * len, 8) + msg = msg .. "\128" .. string.rep("\0", extra) .. len + assert(#msg % 64 == 0) + return msg +end + +local function initH256(H) + H[1] = 0x6a09e667 + H[2] = 0xbb67ae85 + H[3] = 0x3c6ef372 + H[4] = 0xa54ff53a + H[5] = 0x510e527f + H[6] = 0x9b05688c + H[7] = 0x1f83d9ab + H[8] = 0x5be0cd19 + return H +end + +local function digestblock(msg, i, H) + local w = {} + for j = 1, 16 do w[j] = s232num(msg, i + (j - 1) * 4) end + for j = 17, 64 do + local v = w[j - 15] + local s0 = bxor(rrotate(v, 7), rrotate(v, 18), rshift(v, 3)) + v = w[j - 2] + w[j] = w[j - 16] + s0 + w[j - 7] + bxor(rrotate(v, 17), rrotate(v, 19), rshift(v, 10)) + end + + local a, b, c, d, e, f, g, h = H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8] + for i = 1, 64 do + local s0 = bxor(rrotate(a, 2), rrotate(a, 13), rrotate(a, 22)) + local maj = bxor(band(a, b), band(a, c), band(b, c)) + local t2 = s0 + maj + local s1 = bxor(rrotate(e, 6), rrotate(e, 11), rrotate(e, 25)) + local ch = bxor(band(e, f), band(bnot(e), g)) + local t1 = h + s1 + ch + k[i] + w[i] + h, g, f, e, d, c, b, a = g, f, e, d + t1, c, b, a, t1 + t2 + end + + H[1] = band(H[1] + a) + H[2] = band(H[2] + b) + H[3] = band(H[3] + c) + H[4] = band(H[4] + d) + H[5] = band(H[5] + e) + H[6] = band(H[6] + f) + H[7] = band(H[7] + g) + H[8] = band(H[8] + h) +end + +function sha256(msg) + msg = preproc(msg, #msg) + local H = initH256({}) + for i = 1, #msg, 64 do digestblock(msg, i, H) end + return str2hexa(num2s(H[1], 4) .. num2s(H[2], 4) .. num2s(H[3], 4) .. num2s(H[4], 4) .. + num2s(H[5], 4) .. num2s(H[6], 4) .. num2s(H[7], 4) .. num2s(H[8], 4)) +end \ No newline at end of file diff --git a/utils/yunbridge/patches/000-scripts.patch b/utils/yunbridge/patches/000-scripts.patch new file mode 100644 index 000000000..46f21bd5c --- /dev/null +++ b/utils/yunbridge/patches/000-scripts.patch @@ -0,0 +1,18 @@ +--- a/bridge/packet.py ++++ b/bridge/packet.py +@@ -93,12 +93,12 @@ + + def run(self, data): + if data[0] != 'X': +- call(['/usr/bin/blink-start', '100']) ++ #call(['/usr/bin/blink-start', '100']) + return chr(1) + if data[1:4] != '100': +- call(['/usr/bin/blink-start', '100']) ++ #call(['/usr/bin/blink-start', '100']) + return chr(2) +- call(['/usr/bin/blink-stop']) ++ #call(['/usr/bin/blink-stop']) + return chr(0) + '160' # send the actual bridge version + + class PacketReader: