Browse Source

Add all files to source control even though they are messy and don't do much yet

Marcos Kirsch 9 years ago
parent
commit
f52e8f47e6
11 changed files with 543 additions and 0 deletions
  1. 21 0
      README-old.md
  2. 213 0
      b64.lua
  3. 10 0
      b64.py
  4. 23 0
      escape.py
  5. 50 0
      garage.lua
  6. 79 0
      httpserver.lua
  7. 23 0
      init.lua
  8. 30 0
      printTable.lua
  9. 10 0
      remote.html
  10. 25 0
      test.lua
  11. 59 0
      testfile.txt

+ 21 - 0
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?

+ 213 - 0
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

+ 10 - 0
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

+ 23 - 0
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);
+
+'''

+ 50 - 0
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)
+
+

+ 79 - 0
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 = "<h1>Hola mundo</h1>"
+   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

+ 23 - 0
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")

+ 30 - 0
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

+ 10 - 0
remote.html

@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html><head><meta charset="UTF-8"><title>Garage</title></head>
+<body bgcolor="#999999">
+<h1>Garage</h1>
+<form action="" method="POST">
+<input style="width:40%" name="door" type="submit" value="0">
+<input style="width:40%;line-height:80%" name="door" type="submit" value="1">
+</form>
+</body>
+</html>

+ 25 - 0
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)
+

+ 59 - 0
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
+