From f52e8f47e6da8237df482af540e540495ae84188 Mon Sep 17 00:00:00 2001 From: Marcos Kirsch Date: Mon, 2 Feb 2015 19:01:24 -0600 Subject: [PATCH] Add all files to source control even though they are messy and don't do much yet --- README-old.md | 21 +++++ b64.lua | 213 +++++++++++++++++++++++++++++++++++++++++++++++++ b64.py | 10 +++ escape.py | 23 ++++++ garage.lua | 50 ++++++++++++ httpserver.lua | 79 ++++++++++++++++++ init.lua | 23 ++++++ printTable.lua | 30 +++++++ remote.html | 10 +++ test.lua | 25 ++++++ testfile.txt | 59 ++++++++++++++ 11 files changed, 543 insertions(+) create mode 100644 README-old.md create mode 100755 b64.lua create mode 100644 b64.py create mode 100644 escape.py create mode 100644 garage.lua create mode 100644 httpserver.lua create mode 100644 init.lua create mode 100644 printTable.lua create mode 100644 remote.html create mode 100644 test.lua create mode 100644 testfile.txt diff --git a/README-old.md b/README-old.md new file mode 100644 index 0000000..321fa9b --- /dev/null +++ b/README-old.md @@ -0,0 +1,21 @@ +# GARAGE + +This project uses an [ESP2866](http://www.esp8266.com) with [nodeMCU](http://nodemcu.com/index_cn.html) firmware to control a garage door. + +Controlling a garage door from a microcontroller is easy. All you need to do is emulate a push button with a relay and wire it in parallel with the real push button on your garage door motor. + +# Hardware + +I bought a [kit from eBay](http://www.ebay.com/itm/281519483801?_trksid=p2059210.m2749.l2649) that came with most of what I needed: +* A cheap CH430 USB to Serial TTL adapter with 3.3V logic +* A bunch of female to female jumper wires and jumpers +* A somewhat useful carrying board that makes access to GPIO pins impossible as soldered. +* AM1117 5V to 3.3V power supply with 800 mA capacity. +* Female USB cable +* ESP-01 board, which gives access to 2 GPIO pins. + +Separately, I bought [2 relays](http://www.ebay.com/itm/2pcs-3V-Relay-High-Level-Driver-Module-optocouple-Relay-Moduele-for-Arduino-/141523155660?) that can handle way more voltage and current than I need, but are handy because I can drive them with 3.3V logic of the ESP2866. + +# Open issues + +* When the ESP2866 powers up, both GPIO pins are in input mode, which the relay reads as logic high. That's not good, as it would trigger a garage door opening! I need to invert the logic. What's the easiest and cheapest way to do this? diff --git a/b64.lua b/b64.lua new file mode 100755 index 0000000..179897e --- /dev/null +++ b/b64.lua @@ -0,0 +1,213 @@ +#!/usr/local/bin/lua +-- http://lua-users.org/wiki/BaseSixtyFour +-- working lua base64 codec (c) 2006-2008 by Alex Kloss +-- compatible with lua 5.1 +-- http://www.it-rfc.de +-- licensed under the terms of the LGPL2 + +-- bitshift functions (<<, >> equivalent) +-- shift left +function lsh(value,shift) + return (value*(2^shift)) % 256 +end + +-- shift right +function rsh(value,shift) + return math.floor(value/2^shift) % 256 +end + +-- return single bit (for OR) +function bit(x,b) + return (x % 2^b - x % 2^(b-1) > 0) +end + +-- logic OR for number values +function lor(x,y) + result = 0 + for p=1,8 do result = result + (((bit(x,p) or bit(y,p)) == true) and 2^(p-1) or 0) end + return result +end + +-- encryption table +local base64chars = { + [0]='A', + [1]='B', + [2]='C', + [3]='D', + [4]='E', + [5]='F', + [6]='G', + [7]='H', + [8]='I', + [9]='J', + [10]='K', + [11]='L', + [12]='M', + [13]='N', + [14]='O', + [15]='P', + [16]='Q', + [17]='R', + [18]='S', + [19]='T', + [20]='U', + [21]='V', + [22]='W', + [23]='X', + [24]='Y', + [25]='Z', + [26]='a', + [27]='b', + [28]='c', + [29]='d', + [30]='e', + [31]='f', + [32]='g', + [33]='h', + [34]='i', + [35]='j', + [36]='k', + [37]='l', + [38]='m', + [39]='n', + [40]='o', + [41]='p', + [42]='q', + [43]='r', + [44]='s', + [45]='t', + [46]='u', + [47]='v', + [48]='w', + [49]='x', + [50]='y', + [51]='z', + [52]='0', + [53]='1', + [54]='2', + [55]='3', + [56]='4', + [57]='5', + [58]='6', + [59]='7', + [60]='8', + [61]='9', + [62]='-', + [63]='_' +} + +-- function encode +-- encodes input string to base64. +function enc(data) + local bytes = {} + local result = "" + for spos=0,string.len(data)-1,3 do + for byte=1,3 do bytes[byte] = string.byte(string.sub(data,(spos+byte))) or 0 end + result = string.format('%s%s%s%s%s',result,base64chars[rsh(bytes[1],2)],base64chars[lor(lsh((bytes[1] % 4),4), rsh(bytes[2],4))] or "=",((#data-spos) > 1) and base64chars[lor(lsh(bytes[2] % 16,2), rsh(bytes[3],6))] or "=",((#data-spos) > 2) and base64chars[(bytes[3] % 64)] or "=") + end + return result +end + +-- decryption table +local base64bytes = { + ['A']=0, + ['B']=1, + ['C']=2, + ['D']=3, + ['E']=4, + ['F']=5, + ['G']=6, + ['H']=7, + ['I']=8, + ['J']=9, + ['K']=10, + ['L']=11, + ['M']=12, + ['N']=13, + ['O']=14, + ['P']=15, + ['Q']=16, + ['R']=17, + ['S']=18, + ['T']=19, + ['U']=20, + ['V']=21, + ['W']=22, + ['X']=23, + ['Y']=24, + ['Z']=25, + ['a']=26, + ['b']=27, + ['c']=28, + ['d']=29, + ['e']=30, + ['f']=31, + ['g']=32, + ['h']=33, + ['i']=34, + ['j']=35, + ['k']=36, + ['l']=37, + ['m']=38, + ['n']=39, + ['o']=40, + ['p']=41, + ['q']=42, + ['r']=43, + ['s']=44, + ['t']=45, + ['u']=46, + ['v']=47, + ['w']=48, + ['x']=49, + ['y']=50, + ['z']=51, + ['0']=52, + ['1']=53, + ['2']=54, + ['3']=55, + ['4']=56, + ['5']=57, + ['6']=58, + ['7']=59, + ['8']=60, + ['9']=61, + ['-']=62, + ['_']=63, + ['=']=nil +} + +-- function decode +-- decode base64 input to string +function dec(data) + local chars = {} + local result="" + for dpos=0,string.len(data)-1,4 do + for char=1,4 do chars[char] = base64bytes[(string.sub(data,(dpos+char),(dpos+char)) or "=")] end + result = string.format( + '%s%s%s%s', + result, + string.char(lor(lsh(chars[1],2), rsh(chars[2],4))), + (chars[3] ~= nil) and string.char(lor(lsh(chars[2],4), + rsh(chars[3],2))) or "", + (chars[4] ~= nil) and string.char(lor(lsh(chars[3],6) % 192, + (chars[4]))) or "" + ) + end + return result +end + +-- command line if not called as library +if (arg ~= nil) then + local func = 'enc' + for n,v in ipairs(arg) do + if (n > 0) then + if (v == "-h") then print "base64.lua [-e] [-d] text/data" break + elseif (v == "-e") then func = 'enc' + elseif (v == "-d") then func = 'dec' + else print(_G[func](v)) end + end + end +else + module('base64',package.seeall) +end diff --git a/b64.py b/b64.py new file mode 100644 index 0000000..b452c10 --- /dev/null +++ b/b64.py @@ -0,0 +1,10 @@ +import argparse +import base64 + +# Load this source file and strip the header. +initial_data = 'Marcos' + +encoded_data = base64.b64encode(initial_data) + +num_initial = len(initial_data) +print encoded_data diff --git a/escape.py b/escape.py new file mode 100644 index 0000000..2985b1a --- /dev/null +++ b/escape.py @@ -0,0 +1,23 @@ +# esta es una prueba para modificar luatool.py +# http://stackoverflow.com/a/18935765/316875 +from string import maketrans + +def escapeString(a_string): + translationTable = maketrans({"-": r"\-", "]": r"\]", "\\": r"\\", "^": r"\^", "$": r"\$", "*": r"\*", ".": r"\."}) + escaped = a_string.translate(translationTable) + return escaped + +print escapeString("Marcos") + + +#!/usr/bin/python +''' + +intab = "aeiou" +outtab = "12345" +trantab = maketrans(intab, outtab) + +str = "this is string example....wow!!!"; +print str.translate(trantab); + +''' diff --git a/garage.lua b/garage.lua new file mode 100644 index 0000000..b639e07 --- /dev/null +++ b/garage.lua @@ -0,0 +1,50 @@ +print('Welcome to GARAGE') +print(' Created by Marcos Kirsch') + +require "webServer" + +pinGarage = 4 -- GPIO2 +clientTimeoutInSeconds = 10 +port = 80 + +-- Prepare pins +function preparePin(pin) + -- Pins start out configured for input, and the relay has a pulldown resistor + -- in order to prevent from activating on reset. Makes ure to set pin to low + -- BEFORE setting to output, less the relay see it as a toggle. + gpio.write(pin, gpio.LOW) + gpio.mode(pin, gpio.OUTPUT) +end +preparePin(pinGarage) + +-- This functions emulates pushing the button for opening/closing the garage door. +function pushTheButton(pin) + gpio.write(pin, gpio.HIGH) + delayInMicroseconds = 500000 -- half a second should be enough + tmr.delay(delayInMicroseconds) + gpio.write(pin, gpio.LOW) +end + +-- Read the "garage remote" HTML that is served +--file.open("remote.html", "r") +--html = file.read() + +webServer.start(port, clientTimeoutInSeconds) + +-- +--server = net.createServer(net.TCP, clientTimeoutInSeconds) server:listen(port, function(connection) +-- --if server == nil +-- -- print("Server listening on port " .. port) +-- -- return +-- --end +-- connection:on("receive",function(connection,payload) +-- print(payload) -- for debugging only +-- --generates HTML web site +-- connection:send(httpHeader200 .. html) +-- +-- pushTheButton(pinGarage) +-- connection:on("sent",function(connection) connection:close() end) +-- end) +--end) + + diff --git a/httpserver.lua b/httpserver.lua new file mode 100644 index 0000000..eb592d4 --- /dev/null +++ b/httpserver.lua @@ -0,0 +1,79 @@ +-- httpserver +-- Author: Marcos Kirsch +-- This is a very simple HTTP server designed to work on nodemcu (http://nodemcu.com) +-- It can handle GET and POST. +require "printTable" + + +httpserver = {} + + +-- Starts web server in the specified port. +--function httpserver.start(port, clientTimeoutInSeconds, debug) +-- -- Server constants +-- server = net.createServer(net.TCP, clientTimeoutInSeconds) server:listen(port, private.handleRequest) +--end + + +httpserver.private = {} -- not part of the public API + +function httpserver.private.onReceive(connection, payload) + print(payload) -- for debugging + + -- parse payload and decide what to serve. + parsedRequest = private.parseRequest(payload) + httpserver.private.printTable(parsedRequest, 3) + + --generates HTML web site + httpHeader200 = "HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nCache-Control: private, no-store\r\n\r\n" + html = "

Hola mundo

" + connection:send(httpHeader200 .. html) +end + +function httpserver.private.handleRequest(connection) + connection:on("receive", onReceive) + connection:on("sent",function(connection) connection:close() end) +end + +-- given an HTTP request, returns the method (i.e. GET) +function httpserver.private.getRequestMethod(request) + -- HTTP Request Methods. + -- HTTP servers are required to implement at least the GET and HEAD methods + -- http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods + httpMethods = {"GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "OPTIONS", "CONNECT", "PATCH"} + method = nil + for i=1,#httpMethods do + found = string.find(request, httpMethods[i]) + if found == 1 then + break + end + end + return (httpMethods[found]) +end + +-- given an HTTP request, returns a table with all the information. +function httpserver.private.parseRequest(request) + parsedRequest = {} + -- First get the method + + parsedRequest["method"] = httpserver.private.getRequestMethod(request) + if parsedRequest["method"] == nil then + return nil + end + -- Now get each value out of the header, skip the first line + lineNumber = 0 + for line in request:gmatch("[^\r\n]+") do + if lineNumber ~=0 then + -- tag / value are of the style "Host: 10.0.7.15". Break them up. + found, valueIndex = string.find(line, ": ") + if found == nil then + break + end + tag = string.sub(line, 1, found - 1) + value = string.sub(line, found + 2, #line) + parsedRequest[tag] = value + end + lineNumber = lineNumber + 1 + end + return parsedRequest +end diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..e758ccc --- /dev/null +++ b/init.lua @@ -0,0 +1,23 @@ +-- Tell the chip to connect to the access point + +print('Welcome') +wifi.setmode(wifi.STATION) +print('set mode=STATION (mode='..wifi.getmode()..')') +print('MAC: ',wifi.sta.getmac()) +print('chip: ',node.chipid()) +print('heap: ',node.heap()) +wifi.sta.config("Internet","") + +-- Wait until WiFi connection is established + +tmr.alarm(0, 2000, 1, function() + if wifi.sta.getip() == nil then + print("Connecting to AP...") + else + print('IP: ',wifi.sta.getip()) + tmr.stop(0) + end +end) + + +--dofile("garage.lua") diff --git a/printTable.lua b/printTable.lua new file mode 100644 index 0000000..f8cee3d --- /dev/null +++ b/printTable.lua @@ -0,0 +1,30 @@ +-- Print anything - including nested tables +-- Based on but modified from: +-- http://lua-users.org/wiki/TableSerialization +function printTable (tt, indent, done) + done = done or {} + indent = indent or 0 + if tt == nil then + io.write("nil\n") + else + if type(tt) == "table" then + for key, value in pairs (tt) do + io.write(string.rep (" ", indent)) -- indent it + if type (value) == "table" and not done [value] then + done [value] = true + io.write(string.format("[%s] => table\n", tostring (key))); + io.write(string.rep (" ", indent+4)) -- indent it + io.write("(\n"); + table_print (value, indent + 7, done) + io.write(string.rep (" ", indent+4)) -- indent it + io.write(")\n"); + else + io.write(string.format("[%s] => %s\n", + tostring (key), tostring(value))) + end + end + else + io.write(tt .. "\n") + end + end +end diff --git a/remote.html b/remote.html new file mode 100644 index 0000000..8e3631e --- /dev/null +++ b/remote.html @@ -0,0 +1,10 @@ + +Garage + +

Garage

+
+ + +
+ + diff --git a/test.lua b/test.lua new file mode 100644 index 0000000..1b48808 --- /dev/null +++ b/test.lua @@ -0,0 +1,25 @@ +-- figuring out how to parse http header +require "webServer" +--require "printTable" +--require "b64" + +sep = "\r\n" +requestForGet = + "GET /index.html HTTP/1.1" .. sep .. + "Host: 10.0.7.15" .. sep .. + "Accept-Encoding: gzip, deflate" .. sep .. + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" .. sep .. + "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/600.3.18 (KHTML, like Gecko) Version/8.0.3 Safari/600.3.18" .. sep .. + "Accept-Language: en-us" .. sep .. + "Cache-Control: max-age=0" .. sep .. + "Connection: keep-alive" .. sep .. + "" +--print(enc(requestForGet)) +--print(dec(enc(requestForGet))) + +parsedRequest = webServer.private.parseRequest(requestForGet) + +--printTable(parsedRequest, 3) +--printTable(nodemcu-http-server, 3) +--parsedRequest = webServer.parseRequest(requestForGet) + diff --git a/testfile.txt b/testfile.txt new file mode 100644 index 0000000..0605c24 --- /dev/null +++ b/testfile.txt @@ -0,0 +1,59 @@ +testfile + +local foo = bar[i] + +_, _, method, path = string.find(request, "([A-Z]+) (.+) HTTP"); + +00000 + +00010 +0123456789 +00020 +01234567890123456789 +00030 +012345678901234567890123456789 +00040 +0123456789012345678901234567890123456789 +00050 +01234567890123456789012345678901234567890123456789 +00060 +012345678901234567890123456789012345678901234567890123456789 +00070 +0123456789012345678901234567890123456789012345678901234567890123456789 +00080 +01234567890123456789012345678901234567890123456789012345678901234567890123456789 +00090 +012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +00110 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +00120 +01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +00130 +012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +00140 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +00150 +01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +00160 +012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +00170 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +00180 +01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +00190 +012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +00200 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +00210 +01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +00220 +012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +00230 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +00240 +01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +00250 +012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +00260 +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +