- commencé à bosser sur les websocket, ce n'est pas en yaka :-(
- essayé d'installer webide sur NodeMCU, il y a justement un exemple de websocker server, je n'arrive pas encore à comprendre comment cela marche - donc il y a encore pas mal de taf
This commit is contained in:
BIN
Firmware/nodemcu-master-19-modules-2018-11-02-19-36-16-float.bin
Normal file
BIN
Firmware/nodemcu-master-19-modules-2018-11-02-19-36-16-float.bin
Normal file
Binary file not shown.
BIN
Firmware/nodemcu-master-19-modules-2018-11-02-19-36-16-float.pdf
Normal file
BIN
Firmware/nodemcu-master-19-modules-2018-11-02-19-36-16-float.pdf
Normal file
Binary file not shown.
340
Websocket/nodemcu-webide/LICENSE
Executable file
340
Websocket/nodemcu-webide/LICENSE
Executable file
@@ -0,0 +1,340 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
{description}
|
||||
Copyright (C) {year} {fullname}
|
||||
|
||||
This program 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
{signature of Ty Coon}, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
|
||||
27
Websocket/nodemcu-webide/README.md
Executable file
27
Websocket/nodemcu-webide/README.md
Executable file
@@ -0,0 +1,27 @@
|
||||
# **NodeMCU WebIDE** #
|
||||
|
||||

|
||||
|
||||
You may find more details at my instructables:
|
||||
http://www.instructables.com/id/NodeMCU-WebIDE/
|
||||
|
||||
## NodeMCU WebIDE base on 2 core projects:
|
||||
### [nodemcu-httpserver](https://github.com/marcoskirsch/nodemcu-httpserver)
|
||||
A (very) simple web server written in Lua for the ESP8266 running the NodeMCU firmware.
|
||||
|
||||
### [CodeMirror](https://codemirror.net)
|
||||
A versatile text editor implemented in JavaScript for the browser.
|
||||
|
||||
##nodemcu-websocket.lua rewrite from:
|
||||
### [creationix/nodemcu-webide](https://github.com/creationix/nodemcu-webide)
|
||||
A websocket based IDE for nodemcu devices.
|
||||
|
||||
##Todo
|
||||
- allow multiple opened files
|
||||
- auto save file in web browser local storage
|
||||
- redirect NodeMCU output to web browser
|
||||
- new file template
|
||||
- more editor basic feature, such as search
|
||||
- refresh button for reload file list
|
||||
- fix WebSocket memory leakage issue
|
||||
- utilize WebSocket in WebIDE
|
||||
3
Websocket/nodemcu-webide/TODO.md
Executable file
3
Websocket/nodemcu-webide/TODO.md
Executable file
@@ -0,0 +1,3 @@
|
||||
#TODO
|
||||
|
||||
* list out TODO items
|
||||
BIN
Websocket/nodemcu-webide/bin/addons.js.gz
Executable file
BIN
Websocket/nodemcu-webide/bin/addons.js.gz
Executable file
Binary file not shown.
BIN
Websocket/nodemcu-webide/bin/codemirror.js.gz
Executable file
BIN
Websocket/nodemcu-webide/bin/codemirror.js.gz
Executable file
Binary file not shown.
36
Websocket/nodemcu-webide/bin/config.lua
Executable file
36
Websocket/nodemcu-webide/bin/config.lua
Executable file
@@ -0,0 +1,36 @@
|
||||
-- Part of nodemcu-httpserver, contains static configuration for httpserver.
|
||||
-- Author: Sam Dieck
|
||||
|
||||
conf = {}
|
||||
|
||||
conf.hostname = "NODEMCU-WEBIDE" -- DNS host name send to DHCP server (don't use underscore)
|
||||
|
||||
-- Basic Authentication Conf
|
||||
conf.auth = {}
|
||||
conf.auth.enabled = true
|
||||
conf.auth.realm = "nodemcu-httpserver" -- displayed in the login dialog users get
|
||||
conf.auth.user = "toto" -- PLEASE change this
|
||||
conf.auth.password = "tutu" -- PLEASE change this
|
||||
|
||||
-- WiFi configuration
|
||||
conf.wifi = {}
|
||||
-- wifi.STATION (join a WiFi network)
|
||||
-- wifi.SOFTAP (create a WiFi network)
|
||||
-- wifi.STATIONAP (STATION + SOFTAP)
|
||||
conf.wifi.mode = wifi.SOFTAP -- default: SOFTAP (avoid try to connect an invalid AP)
|
||||
|
||||
-- STATION config
|
||||
--conf.wifi.stassid = "YourSSID" -- Name of the WiFi network you want to join
|
||||
--conf.wifi.stapwd = "PleaseInputYourPasswordHere" -- Password for the WiFi network
|
||||
|
||||
-- SOFTAP config
|
||||
conf.wifi.ap = {}
|
||||
--conf.wifi.ap.ssid = "ESP-"..node.chipid() -- Name of the SSID you want to create
|
||||
--conf.wifi.ap.pwd = "12345678"..node.chipid() -- PLEASE change this (at least 8 characters)
|
||||
conf.wifi.ap.ssid = "nodemcu-webide" -- Name of the SSID you want to create
|
||||
conf.wifi.ap.pwd = "12345678" -- PLEASE change this (at least 8 characters)
|
||||
|
||||
conf.wifi.apip = {}
|
||||
conf.wifi.apip.ip = "192.168.111.1"
|
||||
conf.wifi.apip.netmask = "255.255.255.0"
|
||||
conf.wifi.apip.gateway = "0.0.0.0" -- avoid mobile cannot access internet issue
|
||||
15
Websocket/nodemcu-webide/bin/dir.lua
Normal file
15
Websocket/nodemcu-webide/bin/dir.lua
Normal file
@@ -0,0 +1,15 @@
|
||||
-- fonction dir() pour afficher les fichiers dans la flash
|
||||
print("\n dir.lua zf180826.1019 \n")
|
||||
|
||||
function dir()
|
||||
print("\n-------------------------------")
|
||||
l=file.list() i=0
|
||||
for k,v in pairs(l) do
|
||||
i=i+v
|
||||
print(k..string.rep(" ",19-string.len(k)).." : "..v.." bytes")
|
||||
end
|
||||
print("-------------------------------")
|
||||
print('\nUsed: '..i..' bytes\nusage: dofile("file.lua")\n')
|
||||
end
|
||||
|
||||
dir()
|
||||
BIN
Websocket/nodemcu-webide/bin/favicon.ico.gz
Executable file
BIN
Websocket/nodemcu-webide/bin/favicon.ico.gz
Executable file
Binary file not shown.
80
Websocket/nodemcu-webide/bin/file-api.lua
Executable file
80
Websocket/nodemcu-webide/bin/file-api.lua
Executable file
@@ -0,0 +1,80 @@
|
||||
return function (connection, req, args)
|
||||
dofile('httpserver-header.lc')(connection, 200, 'html')
|
||||
|
||||
if req.method == 'POST' then
|
||||
--print('POST method')
|
||||
local rd = req.getRequestData()
|
||||
--print(node.heap())
|
||||
collectgarbage()
|
||||
--print(node.heap())
|
||||
if rd['action'] == 'list' then
|
||||
print('retrieve file list')
|
||||
local l, filelist, n, s, ok, json
|
||||
l = file.list()
|
||||
filelist = {}
|
||||
for n, s in pairs(l) do
|
||||
if ((string.sub(n, -3) ~= '.gz') and (string.sub(n, -3) ~= '.lc')) then
|
||||
filelist[n] = s
|
||||
end
|
||||
end
|
||||
ok, json = pcall(sjson.encode, filelist)
|
||||
if ok then
|
||||
--print(json)
|
||||
connection:send(json)
|
||||
else
|
||||
--print("failed to encode!")
|
||||
end
|
||||
elseif rd['action'] == 'load' then
|
||||
print('load file: '..rd['filename'])
|
||||
file.open(rd['filename'], 'r')
|
||||
local buffer = file.read()
|
||||
while buffer ~= nil do
|
||||
connection:send(buffer)
|
||||
buffer = file.read()
|
||||
end
|
||||
file.close()
|
||||
elseif rd['action'] == 'save' then
|
||||
--print('save file: '..rd['filename'])
|
||||
local data = rd['data']
|
||||
file.open(rd['filename'], 'w+')
|
||||
file.write(data)
|
||||
file.close()
|
||||
connection:send('initial write: ' .. string.len(data))
|
||||
elseif rd['action'] == 'append' then
|
||||
--print('append file: '..rd['filename'])
|
||||
local data = rd['data']
|
||||
file.open(rd['filename'], 'a+')
|
||||
file.seek('end')
|
||||
file.write(data)
|
||||
file.close()
|
||||
connection:send('Append: '..string.len(data))
|
||||
elseif rd['action'] == 'compile' then
|
||||
--print('compile file: '..rd['filename'])
|
||||
node.compile(rd['filename'])
|
||||
local compiledfile = string.sub(rd['filename'], 1, -5)..'.lc'
|
||||
connection:send('Compiled file: <a href="'..compiledfile..'?" target="_blank">'..compiledfile..'</a>')
|
||||
elseif rd['action'] == 'new' then
|
||||
--print('create new file')
|
||||
local i = 1
|
||||
local f = 'new'..i..'.lua'
|
||||
-- find a new file name
|
||||
while file.open(f, 'r') do
|
||||
file.close()
|
||||
i = i + 1
|
||||
f = 'new'..i..'.lua'
|
||||
end
|
||||
file.open(f, 'w+')
|
||||
file.close()
|
||||
connection:send('Created file: '..f)
|
||||
elseif rd['action'] == 'rename' then
|
||||
--print('rename file from "'..rd['filename']..'" to "'..rd['newfilename']..'"')
|
||||
file.rename(rd['filename'], rd['newfilename'])
|
||||
connection:send('Renamed file from "'..rd['filename']..'" to "'..rd['newfilename']..'"')
|
||||
elseif rd['action'] == 'delete' then
|
||||
--print('deleted file: '..rd['filename'])
|
||||
file.remove(rd['filename'])
|
||||
connection:send('Deleted file: '..rd['filename'])
|
||||
end
|
||||
end
|
||||
collectgarbage()
|
||||
end
|
||||
14
Websocket/nodemcu-webide/bin/hello-world.lua
Executable file
14
Websocket/nodemcu-webide/bin/hello-world.lua
Executable file
@@ -0,0 +1,14 @@
|
||||
return function (connection, req, args)
|
||||
dofile('httpserver-header.lc')(connection, 200, 'html')
|
||||
|
||||
connection:send([===[<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Hello World!</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
</body>
|
||||
</html>]===])
|
||||
end
|
||||
30
Websocket/nodemcu-webide/bin/httpserver-basicauth.lua
Executable file
30
Websocket/nodemcu-webide/bin/httpserver-basicauth.lua
Executable file
@@ -0,0 +1,30 @@
|
||||
-- httpserver-basicauth.lua
|
||||
-- Part of nodemcu-httpserver, authenticates a user using http basic auth.
|
||||
-- Author: Sam Dieck
|
||||
|
||||
basicAuth = {}
|
||||
|
||||
-- Parse basic auth http header.
|
||||
-- Returns the username if header contains valid credentials,
|
||||
-- nil otherwise.
|
||||
function basicAuth.authenticate(header)
|
||||
local credentials_enc = header:match("Authorization: Basic ([A-Za-z0-9+/=]+)")
|
||||
if not credentials_enc then
|
||||
return nil
|
||||
end
|
||||
local credentials = encoder.fromBase64(credentials_enc)
|
||||
local user, pwd = credentials:match("^(.*):(.*)$")
|
||||
if user ~= conf.auth.user or pwd ~= conf.auth.password then
|
||||
print("httpserver-basicauth: User \"" .. user .. "\": Access denied.")
|
||||
return nil
|
||||
end
|
||||
print("httpserver-basicauth: User \"" .. user .. "\": Authenticated.")
|
||||
print("toto",node.heap())
|
||||
return user
|
||||
end
|
||||
|
||||
function basicAuth.authErrorHeader()
|
||||
return "WWW-Authenticate: Basic realm=\"" .. conf.auth.realm .. "\""
|
||||
end
|
||||
|
||||
return basicAuth
|
||||
67
Websocket/nodemcu-webide/bin/httpserver-connection.lua
Executable file
67
Websocket/nodemcu-webide/bin/httpserver-connection.lua
Executable file
@@ -0,0 +1,67 @@
|
||||
-- httpserver-connection
|
||||
-- Part of nodemcu-httpserver, provides a buffered connection object that can handle multiple
|
||||
-- consecutive send() calls, and buffers small payloads to send once they get big.
|
||||
-- For this to work, it must be used from a coroutine and owner is responsible for the final
|
||||
-- flush() and for closing the connection.
|
||||
-- Author: Philip Gladstone, Marcos Kirsch
|
||||
|
||||
BufferedConnection = {}
|
||||
|
||||
-- parameter is the nodemcu-firmware connection
|
||||
function BufferedConnection:new(connection)
|
||||
local newInstance = {}
|
||||
newInstance.connection = connection
|
||||
newInstance.size = 0
|
||||
newInstance.data = {}
|
||||
|
||||
function newInstance:flush()
|
||||
if self.size > 0 then
|
||||
self.connection:send(table.concat(self.data, ""))
|
||||
self.data = {}
|
||||
self.size = 0
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function newInstance:send(payload)
|
||||
local flushthreshold = 1400
|
||||
|
||||
local newsize = self.size + payload:len()
|
||||
while newsize > flushthreshold do
|
||||
--STEP1: cut out piece from payload to complete threshold bytes in table
|
||||
local piecesize = flushthreshold - self.size
|
||||
local piece = payload:sub(1, piecesize)
|
||||
payload = payload:sub(piecesize + 1, -1)
|
||||
--STEP2: insert piece into table
|
||||
table.insert(self.data, piece)
|
||||
self.size = self.size + piecesize --size should be same as flushthreshold
|
||||
--STEP3: flush entire table
|
||||
if self:flush() then
|
||||
coroutine.yield()
|
||||
end
|
||||
--at this point, size should be 0, because the table was just flushed
|
||||
newsize = self.size + payload:len()
|
||||
end
|
||||
|
||||
--at this point, whatever is left in payload should be <= flushthreshold
|
||||
local plen = payload:len()
|
||||
if plen == flushthreshold then
|
||||
--case 1: what is left in payload is exactly flushthreshold bytes (boundary case), so flush it
|
||||
table.insert(self.data, payload)
|
||||
self.size = self.size + plen
|
||||
if self:flush() then
|
||||
coroutine.yield()
|
||||
end
|
||||
elseif payload:len() then
|
||||
--case 2: what is left in payload is less than flushthreshold, so just leave it in the table
|
||||
table.insert(self.data, payload)
|
||||
self.size = self.size + plen
|
||||
--else, case 3: nothing left in payload, so do nothing
|
||||
end
|
||||
end
|
||||
|
||||
return newInstance
|
||||
end
|
||||
|
||||
return BufferedConnection
|
||||
22
Websocket/nodemcu-webide/bin/httpserver-error.lua
Executable file
22
Websocket/nodemcu-webide/bin/httpserver-error.lua
Executable file
@@ -0,0 +1,22 @@
|
||||
-- httpserver-error.lua
|
||||
-- Part of nodemcu-httpserver, handles sending error pages to client.
|
||||
-- Author: Marcos Kirsch
|
||||
|
||||
return function (connection, req, args)
|
||||
|
||||
-- @TODO: would be nice to use httpserver-header.lua
|
||||
local function getHeader(connection, code, errorString, extraHeaders, mimeType)
|
||||
local header = "HTTP/1.0 " .. code .. " " .. errorString .. "\r\nServer: nodemcu-httpserver\r\nContent-Type: " .. mimeType .. "\r\n"
|
||||
for i, extraHeader in ipairs(extraHeaders) do
|
||||
header = header .. extraHeader .. "\r\n"
|
||||
end
|
||||
header = header .. "connection: close\r\n\r\n"
|
||||
return header
|
||||
end
|
||||
|
||||
print("Error " .. args.code .. ": " .. args.errorString)
|
||||
args.headers = args.headers or {}
|
||||
connection:send(getHeader(connection, args.code, args.errorString, args.headers, "text/html"))
|
||||
connection:send("<html><head><title>" .. args.code .. " - " .. args.errorString .. "</title></head><body><h1>" .. args.code .. " - " .. args.errorString .. "</h1></body></html>\r\n")
|
||||
|
||||
end
|
||||
31
Websocket/nodemcu-webide/bin/httpserver-header.lua
Executable file
31
Websocket/nodemcu-webide/bin/httpserver-header.lua
Executable file
@@ -0,0 +1,31 @@
|
||||
-- httpserver-header.lua
|
||||
-- Part of nodemcu-httpserver, knows how to send an HTTP header.
|
||||
-- Author: Marcos Kirsch
|
||||
|
||||
return function (connection, code, extension, isGzipped)
|
||||
|
||||
local function getHTTPStatusString(code)
|
||||
local codez = {[200]="OK", [304]="Not Modified", [400]="Bad Request", [404]="Not Found", [500]="Internal Server Error",}
|
||||
local myResult = codez[code]
|
||||
-- enforce returning valid http codes all the way throughout?
|
||||
if myResult then return myResult else return "Not Implemented" end
|
||||
end
|
||||
|
||||
local function getMimeType(ext)
|
||||
-- A few MIME types. Keep list short. If you need something that is missing, let's add it.
|
||||
local mt = {css = "text/css", gif = "image/gif", html = "text/html", ico = "image/x-icon", jpeg = "image/jpeg", jpg = "image/jpeg", js = "application/javascript", json = "application/json", png = "image/png", xml = "text/xml", svg = "image/svg+xml"}
|
||||
if mt[ext] then return mt[ext] else return "text/plain" end
|
||||
end
|
||||
|
||||
local mimeType = getMimeType(extension)
|
||||
|
||||
connection:send("HTTP/1.0 " .. code .. " " .. getHTTPStatusString(code) .. "\r\nServer: nodemcu-httpserver\r\nContent-Type: " .. mimeType .. "\r\n")
|
||||
if isGzipped then
|
||||
connection:send("Cache-Control: max-age=2592000\r\nContent-Encoding: gzip\r\n")
|
||||
--TODO: handle Last-Modified for each file instead of use a fixed dummy date time
|
||||
connection:send("Last-Modified: Fri, 01 Jan 2016 00:00:00 GMT\r\n")
|
||||
else
|
||||
connection:send("Cache-Control: private, no-store\r\n")
|
||||
end
|
||||
connection:send("Connection: close\r\n\r\n")
|
||||
end
|
||||
127
Websocket/nodemcu-webide/bin/httpserver-request.lua
Executable file
127
Websocket/nodemcu-webide/bin/httpserver-request.lua
Executable file
@@ -0,0 +1,127 @@
|
||||
-- httpserver-request
|
||||
-- Part of nodemcu-httpserver, parses incoming client requests.
|
||||
-- Author: Marcos Kirsch
|
||||
|
||||
local function validateMethod(method)
|
||||
local httpMethods = {GET=true, HEAD=true, POST=true, PUT=true, DELETE=true, TRACE=true, OPTIONS=true, CONNECT=true, PATCH=true}
|
||||
-- default for non-existent attributes returns nil, which evaluates to false
|
||||
return httpMethods[method]
|
||||
end
|
||||
|
||||
local function uriToFilename(uri)
|
||||
return string.sub(uri, 2, -1)
|
||||
end
|
||||
|
||||
local function hex_to_char(x)
|
||||
return string.char(tonumber(x, 16))
|
||||
end
|
||||
|
||||
local function uri_decode(input)
|
||||
return input:gsub("%+", " "):gsub("%%(%x%x)", hex_to_char)
|
||||
end
|
||||
|
||||
local function parseArgs(args)
|
||||
local r = {}; i=1
|
||||
if args == nil or args == "" then return r end
|
||||
for arg in string.gmatch(args, "([^&]+)") do
|
||||
local name, value = string.match(arg, "(.*)=(.*)")
|
||||
if name ~= nil then r[name] = uri_decode(value) end
|
||||
i = i + 1
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
local function parseFormData(body)
|
||||
local data = {}
|
||||
--print("Parsing Form Data")
|
||||
for kv in body.gmatch(body, "%s*&?([^=]+=[^&]+)") do
|
||||
local key, value = string.match(kv, "(.*)=(.*)")
|
||||
--print("Parsed: " .. key .. " => " .. value)
|
||||
data[key] = uri_decode(value)
|
||||
end
|
||||
return data
|
||||
end
|
||||
|
||||
local function isCheckModifiedRequest(payload)
|
||||
return function ()
|
||||
local checkResult = (string.find(payload, 'If%-Modified%-Since: ') ~= nil)
|
||||
return checkResult
|
||||
end
|
||||
end
|
||||
|
||||
local function getRequestData(payload)
|
||||
local requestData
|
||||
return function ()
|
||||
--print("Getting Request Data")
|
||||
if requestData then
|
||||
return requestData
|
||||
else
|
||||
--print("payload = [" .. payload .. "]")
|
||||
local mimeType = string.match(payload, "Content%-Type: ([%w/-]+)")
|
||||
local bodyStart = payload:find("\r\n\r\n", 1, true)
|
||||
local body = payload:sub(bodyStart, #payload)
|
||||
payload = nil
|
||||
collectgarbage()
|
||||
--print("mimeType = [" .. mimeType .. "]")
|
||||
--print("bodyStart = [" .. bodyStart .. "]")
|
||||
--print("body = [" .. body .. "]")
|
||||
if mimeType == "application/json" then
|
||||
--print("JSON: " .. body)
|
||||
requestData = sjson.decode(body)
|
||||
elseif mimeType == "application/x-www-form-urlencoded" then
|
||||
requestData = parseFormData(body)
|
||||
else
|
||||
requestData = {}
|
||||
end
|
||||
return requestData
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function parseUri(uri)
|
||||
local r = {}
|
||||
local filename
|
||||
local ext
|
||||
local fullExt = {}
|
||||
|
||||
if uri == nil then return r end
|
||||
if uri == "/" then uri = "/index.html" end
|
||||
questionMarkPos, b, c, d, e, f = uri:find("?")
|
||||
if questionMarkPos == nil then
|
||||
r.file = uri:sub(1, questionMarkPos)
|
||||
r.args = {}
|
||||
else
|
||||
r.file = uri:sub(1, questionMarkPos - 1)
|
||||
r.args = parseArgs(uri:sub(questionMarkPos+1, #uri))
|
||||
end
|
||||
filename = r.file
|
||||
while filename:match("%.") do
|
||||
filename,ext = filename:match("(.+)%.(.+)")
|
||||
table.insert(fullExt,1,ext)
|
||||
end
|
||||
if #fullExt > 1 and fullExt[#fullExt] == 'gz' then
|
||||
r.ext = fullExt[#fullExt-1]
|
||||
r.isGzipped = true
|
||||
elseif #fullExt >= 1 then
|
||||
r.ext = fullExt[#fullExt]
|
||||
end
|
||||
r.isScript = r.ext == "lua" or r.ext == "lc"
|
||||
r.file = uriToFilename(r.file)
|
||||
return r
|
||||
end
|
||||
|
||||
-- Parses the client's request. Returns a dictionary containing pretty much everything
|
||||
-- the server needs to know about the uri.
|
||||
return function (request)
|
||||
--print("Request: \n", request)
|
||||
local e = request:find("\r\n", 1, true)
|
||||
if not e then return nil end
|
||||
local line = request:sub(1, e - 1)
|
||||
local r = {}
|
||||
_, i, r.method, r.request = line:find("^([A-Z]+) (.-) HTTP/[1-9]+.[0-9]+$")
|
||||
r.methodIsValid = validateMethod(r.method)
|
||||
r.uri = parseUri(r.request)
|
||||
r.isCheckModifiedRequest = isCheckModifiedRequest(request)
|
||||
r.getRequestData = getRequestData(request)
|
||||
return r
|
||||
end
|
||||
39
Websocket/nodemcu-webide/bin/httpserver-static.lua
Executable file
39
Websocket/nodemcu-webide/bin/httpserver-static.lua
Executable file
@@ -0,0 +1,39 @@
|
||||
-- httpserver-static.lua
|
||||
-- Part of nodemcu-httpserver, handles sending static files to client.
|
||||
-- Author: Marcos Kirsch
|
||||
|
||||
return function (connection, req, args)
|
||||
--print("Begin sending:", args.file)
|
||||
--print("node.heap(): ", node.heap())
|
||||
if args.isGzipped and req.isCheckModifiedRequest() then
|
||||
-- todo: really check if file updated
|
||||
dofile("httpserver-header.lc")(connection, 304, args.ext, args.isGzipped)
|
||||
else
|
||||
dofile("httpserver-header.lc")(connection, 200, args.ext, args.isGzipped)
|
||||
-- Send file in little chunks
|
||||
local continue = true
|
||||
local size = file.list()[args.file]
|
||||
local bytesSent = 0
|
||||
-- Chunks larger than 1024 don't work.
|
||||
-- https://github.com/nodemcu/nodemcu-firmware/issues/1075
|
||||
local chunkSize = 1024
|
||||
while continue do
|
||||
collectgarbage()
|
||||
|
||||
-- NodeMCU file API lets you open 1 file at a time.
|
||||
-- So we need to open, seek, close each time in order
|
||||
-- to support multiple simultaneous clients.
|
||||
file.open(args.file)
|
||||
file.seek("set", bytesSent)
|
||||
local chunk = file.read(chunkSize)
|
||||
file.close()
|
||||
|
||||
connection:send(chunk)
|
||||
bytesSent = bytesSent + #chunk
|
||||
chunk = nil
|
||||
--print("Sent: " .. bytesSent .. " of " .. size)
|
||||
if bytesSent == size then continue = false end
|
||||
end
|
||||
--print("Finished sending: ", args.file)
|
||||
end
|
||||
end
|
||||
135
Websocket/nodemcu-webide/bin/httpserver-websocket.lua
Executable file
135
Websocket/nodemcu-webide/bin/httpserver-websocket.lua
Executable file
@@ -0,0 +1,135 @@
|
||||
--rewrite from https://github.com/creationix/nodemcu-webide
|
||||
|
||||
local function decode(chunk)
|
||||
if #chunk < 2 then return end
|
||||
local second = string.byte(chunk, 2)
|
||||
local len = bit.band(second, 0x7f)
|
||||
local offset
|
||||
if len == 126 then
|
||||
if #chunk < 4 then return end
|
||||
len = bit.bor(
|
||||
bit.lshift(string.byte(chunk, 3), 8),
|
||||
string.byte(chunk, 4))
|
||||
offset = 4
|
||||
elseif len == 127 then
|
||||
if #chunk < 10 then return end
|
||||
len = bit.bor(
|
||||
-- Ignore lengths longer than 32bit
|
||||
bit.lshift(string.byte(chunk, 7), 24),
|
||||
bit.lshift(string.byte(chunk, 8), 16),
|
||||
bit.lshift(string.byte(chunk, 9), 8),
|
||||
string.byte(chunk, 10))
|
||||
offset = 10
|
||||
else
|
||||
offset = 2
|
||||
end
|
||||
local mask = bit.band(second, 0x80) > 0
|
||||
if mask then
|
||||
offset = offset + 4
|
||||
end
|
||||
if #chunk < offset + len then return end
|
||||
|
||||
local first = string.byte(chunk, 1)
|
||||
local payload = string.sub(chunk, offset + 1, offset + len)
|
||||
assert(#payload == len, "Length mismatch")
|
||||
if mask then
|
||||
payload = crypto.mask(payload, string.sub(chunk, offset - 3, offset))
|
||||
end
|
||||
local extra = string.sub(chunk, offset + len + 1)
|
||||
local opcode = bit.band(first, 0xf)
|
||||
return extra, payload, opcode
|
||||
end
|
||||
|
||||
local function encode(payload, opcode)
|
||||
opcode = opcode or 2
|
||||
assert(type(opcode) == "number", "opcode must be number")
|
||||
assert(type(payload) == "string", "payload must be string")
|
||||
local len = #payload
|
||||
local head = string.char(
|
||||
bit.bor(0x80, opcode),
|
||||
bit.bor(len < 126 and len or len < 0x10000 and 126 or 127)
|
||||
)
|
||||
if len >= 0x10000 then
|
||||
head = head .. string.char(
|
||||
0,0,0,0, -- 32 bit length is plenty, assume zero for rest
|
||||
bit.band(bit.rshift(len, 24), 0xff),
|
||||
bit.band(bit.rshift(len, 16), 0xff),
|
||||
bit.band(bit.rshift(len, 8), 0xff),
|
||||
bit.band(len, 0xff)
|
||||
)
|
||||
elseif len >= 126 then
|
||||
head = head .. string.char(bit.band(bit.rshift(len, 8), 0xff), bit.band(len, 0xff))
|
||||
end
|
||||
return head .. payload
|
||||
end
|
||||
|
||||
local guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
|
||||
local function acceptKey(key)
|
||||
return crypto.toBase64(crypto.hash("sha1", key .. guid))
|
||||
end
|
||||
|
||||
return function (connection, payload)
|
||||
local buffer = false
|
||||
local socket = {}
|
||||
local queue = {}
|
||||
local waiting = false
|
||||
local function onSend()
|
||||
if queue[1] then
|
||||
local data = table.remove(queue, 1)
|
||||
return connection:send(data, onSend)
|
||||
end
|
||||
waiting = false
|
||||
end
|
||||
function socket.send(...)
|
||||
local data = encode(...)
|
||||
if not waiting then
|
||||
waiting = true
|
||||
connection:send(data, onSend)
|
||||
else
|
||||
queue[#queue + 1] = data
|
||||
end
|
||||
collectgarbage()
|
||||
print(node.heap())
|
||||
end
|
||||
|
||||
connection:on("receive", function(_, chunk)
|
||||
if buffer then
|
||||
buffer = buffer .. chunk
|
||||
while true do
|
||||
local extra, payload, opcode = decode(buffer)
|
||||
if not extra then return end
|
||||
buffer = extra
|
||||
socket.onmessage(payload, opcode)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
connection:on("sent", function(_, _)
|
||||
if socket.onsent ~= nil then
|
||||
socket.onsent()
|
||||
end
|
||||
end)
|
||||
|
||||
connection:on("disconnection", function(_, _)
|
||||
if socket.onclose ~= nil then
|
||||
socket.onclose()
|
||||
end
|
||||
end)
|
||||
|
||||
local req = dofile("httpserver-request.lc")(payload)
|
||||
local key = payload:match("Sec%-WebSocket%-Key: ([A-Za-z0-9+/=]+)")
|
||||
local fileExists = file.open(req.uri.file, "r")
|
||||
file.close()
|
||||
if req.method == "GET" and key and fileExists then
|
||||
connection:send(
|
||||
"HTTP/1.1 101 Switching Protocols\r\n" ..
|
||||
"Upgrade: websocket\r\nConnection: Upgrade\r\n" ..
|
||||
"Sec-WebSocket-Accept: " .. acceptKey(key) .. "\r\n\r\n",
|
||||
function () dofile(req.uri.file)(socket) end)
|
||||
buffer = ""
|
||||
else
|
||||
connection:send(
|
||||
"HTTP/1.1 404 Not Found\r\nConnection: Close\r\n\r\n",
|
||||
connection.close)
|
||||
end
|
||||
end
|
||||
171
Websocket/nodemcu-webide/bin/httpserver.lua
Executable file
171
Websocket/nodemcu-webide/bin/httpserver.lua
Executable file
@@ -0,0 +1,171 @@
|
||||
-- httpserver
|
||||
-- Author: Marcos Kirsch
|
||||
|
||||
-- Starts web server in the specified port.
|
||||
return function (port)
|
||||
|
||||
local s = net.createServer(net.TCP, 10) -- 10 seconds client timeout
|
||||
s:listen(
|
||||
port,
|
||||
function (connection)
|
||||
|
||||
-- This variable holds the thread (actually a Lua coroutine) used for sending data back to the user.
|
||||
-- We do it in a separate thread because we need to send in little chunks and wait for the onSent event
|
||||
-- before we can send more, or we risk overflowing the mcu's buffer.
|
||||
local connectionThread
|
||||
|
||||
local allowStatic = {GET=true, HEAD=true, POST=false, PUT=false, DELETE=false, TRACE=false, OPTIONS=false, CONNECT=false, PATCH=false}
|
||||
|
||||
local function startServing(fileServeFunction, connection, req, args)
|
||||
connectionThread = coroutine.create(function(fileServeFunction, bufferedConnection, req, args)
|
||||
fileServeFunction(bufferedConnection, req, args)
|
||||
-- The bufferedConnection may still hold some data that hasn't been sent. Flush it before closing.
|
||||
if not bufferedConnection:flush() then
|
||||
connection:close()
|
||||
connectionThread = nil
|
||||
end
|
||||
end)
|
||||
|
||||
local BufferedConnectionClass = dofile("httpserver-connection.lc")
|
||||
local bufferedConnection = BufferedConnectionClass:new(connection)
|
||||
local status, err = coroutine.resume(connectionThread, fileServeFunction, bufferedConnection, req, args)
|
||||
if not status then
|
||||
print("Error: ", err)
|
||||
end
|
||||
end
|
||||
|
||||
local function handleRequest(connection, req)
|
||||
collectgarbage()
|
||||
local method = req.method
|
||||
local uri = req.uri
|
||||
local fileServeFunction = nil
|
||||
|
||||
if #(uri.file) > 32 then
|
||||
-- nodemcu-firmware cannot handle long filenames.
|
||||
uri.args = {code = 400, errorString = "Bad Request"}
|
||||
fileServeFunction = dofile("httpserver-error.lc")
|
||||
else
|
||||
local fileExists = file.open(uri.file, "r")
|
||||
file.close()
|
||||
|
||||
if not fileExists then
|
||||
-- gzip check
|
||||
fileExists = file.open(uri.file .. ".gz", "r")
|
||||
file.close()
|
||||
|
||||
if fileExists then
|
||||
--print("gzip variant exists, serving that one")
|
||||
uri.file = uri.file .. ".gz"
|
||||
uri.isGzipped = true
|
||||
end
|
||||
end
|
||||
|
||||
if not fileExists then
|
||||
uri.args = {code = 404, errorString = "Not Found"}
|
||||
fileServeFunction = dofile("httpserver-error.lc")
|
||||
elseif uri.isScript then
|
||||
fileServeFunction = dofile(uri.file)
|
||||
else
|
||||
if allowStatic[method] then
|
||||
uri.args = {file = uri.file, ext = uri.ext, isGzipped = uri.isGzipped}
|
||||
fileServeFunction = dofile("httpserver-static.lc")
|
||||
else
|
||||
uri.args = {code = 405, errorString = "Method not supported"}
|
||||
fileServeFunction = dofile("httpserver-error.lc")
|
||||
end
|
||||
end
|
||||
end
|
||||
startServing(fileServeFunction, connection, req, uri.args)
|
||||
end
|
||||
|
||||
local function onReceive(connection, payload)
|
||||
--websocket
|
||||
if payload:find("Upgrade: websocket") then
|
||||
dofile('httpserver-websocket.lc')(connection, payload)
|
||||
return
|
||||
end
|
||||
|
||||
collectgarbage()
|
||||
local auth
|
||||
local user = "Anonymous"
|
||||
|
||||
-- as suggest by anyn99 (https://github.com/marcoskirsch/nodemcu-httpserver/issues/36#issuecomment-167442461)
|
||||
-- Some browsers send the POST data in multiple chunks.
|
||||
-- Collect data packets until the size of HTTP body meets the Content-Length stated in header
|
||||
if payload:find("Content%-Length:") or bBodyMissing then
|
||||
if fullPayload then fullPayload = fullPayload .. payload else fullPayload = payload end
|
||||
if (tonumber(string.match(fullPayload, "%d+", fullPayload:find("Content%-Length:")+16)) > #fullPayload:sub(fullPayload:find("\r\n\r\n", 1, true)+4, #fullPayload)) then
|
||||
bBodyMissing = true
|
||||
return
|
||||
else
|
||||
--print("HTTP packet assembled! size: "..#fullPayload)
|
||||
payload = fullPayload
|
||||
fullPayload, bBodyMissing = nil
|
||||
end
|
||||
end
|
||||
collectgarbage()
|
||||
|
||||
-- parse payload and decide what to serve.
|
||||
local req = dofile("httpserver-request.lc")(payload)
|
||||
print(req.method .. ": " .. req.request)
|
||||
if conf.auth.enabled then
|
||||
auth = dofile("httpserver-basicauth.lc")
|
||||
user = auth.authenticate(payload) -- authenticate returns nil on failed auth
|
||||
req.user = user -- store authenticated user to req table
|
||||
end
|
||||
|
||||
if user and req.methodIsValid and (req.method == "GET" or req.method == "POST" or req.method == "PUT") then
|
||||
handleRequest(connection, req)
|
||||
else
|
||||
local args = {}
|
||||
local fileServeFunction = dofile("httpserver-error.lc")
|
||||
if not user then
|
||||
args = {code = 401, errorString = "Not Authorized", headers = {auth.authErrorHeader()}}
|
||||
elseif req.methodIsValid then
|
||||
args = {code = 501, errorString = "Not Implemented"}
|
||||
else
|
||||
args = {code = 400, errorString = "Bad Request"}
|
||||
end
|
||||
startServing(fileServeFunction, connection, req, args)
|
||||
end
|
||||
end
|
||||
|
||||
local function onSent(connection, payload)
|
||||
collectgarbage()
|
||||
if connectionThread then
|
||||
local connectionThreadStatus = coroutine.status(connectionThread)
|
||||
if connectionThreadStatus == "suspended" then
|
||||
-- Not finished sending file, resume.
|
||||
local status, err = coroutine.resume(connectionThread)
|
||||
if not status then
|
||||
print(err)
|
||||
end
|
||||
elseif connectionThreadStatus == "dead" then
|
||||
-- We're done sending file.
|
||||
connection:close()
|
||||
connectionThread = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function onDisconnect(connection, payload)
|
||||
if connectionThread then
|
||||
connectionThread = nil
|
||||
collectgarbage()
|
||||
end
|
||||
end
|
||||
|
||||
connection:on("receive", onReceive)
|
||||
connection:on("sent", onSent)
|
||||
connection:on("disconnection", onDisconnect)
|
||||
|
||||
end
|
||||
)
|
||||
-- false and nil evaluate as false
|
||||
local ip = wifi.sta.getip()
|
||||
if not ip then ip = wifi.ap.getip() end
|
||||
if not ip then ip = "unknown IP" end
|
||||
print("nodemcu-httpserver running at http://" .. ip .. ":" .. port)
|
||||
return s
|
||||
|
||||
end
|
||||
BIN
Websocket/nodemcu-webide/bin/index.html.gz
Executable file
BIN
Websocket/nodemcu-webide/bin/index.html.gz
Executable file
Binary file not shown.
BIN
Websocket/nodemcu-webide/bin/index.js.gz
Executable file
BIN
Websocket/nodemcu-webide/bin/index.js.gz
Executable file
Binary file not shown.
115
Websocket/nodemcu-webide/bin/initz.lua
Executable file
115
Websocket/nodemcu-webide/bin/initz.lua
Executable file
@@ -0,0 +1,115 @@
|
||||
-- init adc
|
||||
--if adc.force_init_mode(adc.INIT_VDD33) then
|
||||
-- node.restart()
|
||||
--end
|
||||
|
||||
-- init and clear ws2812
|
||||
--ws2812.init()
|
||||
--ws2812.write(string.char(0):rep(3096))
|
||||
|
||||
-- init config
|
||||
dofile('config.lua')
|
||||
|
||||
-- init WiFi
|
||||
-- Tell the chip to connect to the access point
|
||||
wifi.setmode(conf.wifi.mode)
|
||||
print('set (mode='..wifi.getmode()..')')
|
||||
|
||||
if (conf.wifi.mode == wifi.SOFTAP) or (conf.wifi.mode == wifi.STATIONAP) then
|
||||
print('AP MAC: ', wifi.ap.getmac())
|
||||
wifi.ap.config(conf.wifi.ap)
|
||||
wifi.ap.setip(conf.wifi.apip)
|
||||
end
|
||||
if (conf.wifi.mode == wifi.STATION) or (conf.wifi.mode == wifi.STATIONAP) then
|
||||
print('Client MAC: ', wifi.sta.getmac())
|
||||
wifi.sta.sethostname(conf.hostname)
|
||||
wifi.sta.config(conf.wifi.stassid, conf.wifi.stapwd, 1)
|
||||
end
|
||||
collectgarbage()
|
||||
|
||||
-- show system info
|
||||
print('chip: ',node.chipid())
|
||||
print('heap: ',node.heap())
|
||||
|
||||
-- Compile server code and remove original .lua files.
|
||||
-- This only happens the first time afer the .lua files are uploaded.
|
||||
local compileAndRemoveIfNeeded = function(f)
|
||||
if file.open(f) then
|
||||
file.close()
|
||||
print('Compiling:', f)
|
||||
node.compile(f)
|
||||
file.remove(f)
|
||||
collectgarbage()
|
||||
end
|
||||
end
|
||||
|
||||
local serverFiles = {
|
||||
'httpserver.lua',
|
||||
'httpserver-basicauth.lua',
|
||||
'httpserver-connection.lua',
|
||||
'httpserver-error.lua',
|
||||
'httpserver-header.lua',
|
||||
'httpserver-request.lua',
|
||||
'httpserver-static.lua',
|
||||
'httpserver-websocket.lua',
|
||||
'file-api.lua'
|
||||
}
|
||||
for i, f in ipairs(serverFiles) do compileAndRemoveIfNeeded(f) end
|
||||
|
||||
compileAndRemoveIfNeeded = nil
|
||||
serverFiles = nil
|
||||
i = nil
|
||||
f = nil
|
||||
collectgarbage()
|
||||
|
||||
-- pre-compile other lua files
|
||||
local l, f, s
|
||||
l = file.list();
|
||||
for f, s in pairs(l) do
|
||||
if ((string.sub(f, -4) == '.lua') and (f ~= 'config.lua') and (f ~= 'init.lua')) then
|
||||
print('Pre-compiling:', f)
|
||||
node.compile(f)
|
||||
collectgarbage()
|
||||
end
|
||||
end
|
||||
l = nil
|
||||
f = nil
|
||||
s = nil
|
||||
collectgarbage()
|
||||
|
||||
-- check and show STATION mode obtained IP
|
||||
if (wifi.getmode() == wifi.STATION) or (wifi.getmode() == wifi.STATIONAP) then
|
||||
local joinCounter = 0
|
||||
local joinMaxAttempts = 5
|
||||
tmr.alarm(0, 3000, 1, function()
|
||||
local ip = wifi.sta.getip()
|
||||
if ip == nil and joinCounter < joinMaxAttempts then
|
||||
print('Connecting to WiFi Access Point ...')
|
||||
joinCounter = joinCounter + 1
|
||||
else
|
||||
if joinCounter == joinMaxAttempts then
|
||||
print('Failed to connect to WiFi Access Point.')
|
||||
print('Fall back to SOFTAP.')
|
||||
wifi.setmode(wifi.SOFTAP)
|
||||
wifi.ap.config(conf.wifi.ap)
|
||||
wifi.ap.setip(conf.wifi.apip)
|
||||
else
|
||||
print('IP: ',ip)
|
||||
mdns.register(conf.hostname, { description="NodeMCU WebIDE", service="http", port=80, location='In your ESP board' })
|
||||
sntp.sync('pool.ntp.org')
|
||||
end
|
||||
tmr.stop(0)
|
||||
joinCounter = nil
|
||||
joinMaxAttempts = nil
|
||||
collectgarbage()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- start the nodemcu-httpserver in port 80
|
||||
if (not not wifi.sta.getip()) or (not not wifi.ap.getip()) then
|
||||
dofile("httpserver.lc")(80)
|
||||
collectgarbage()
|
||||
end
|
||||
|
||||
--dofile('led-stick.lc')()
|
||||
150
Websocket/nodemcu-webide/bin/led-matrix.html
Executable file
150
Websocket/nodemcu-webide/bin/led-matrix.html
Executable file
@@ -0,0 +1,150 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=0.67">
|
||||
<title>LED Matrix</title>
|
||||
<style>
|
||||
#colorPicker {
|
||||
padding: 4px;
|
||||
background: #000;
|
||||
}
|
||||
#ledMatrix {
|
||||
width: 320px;
|
||||
height: 192px;
|
||||
padding: 16px;
|
||||
-webkit-border-radius:8px;
|
||||
-moz-border-radius: 8px;
|
||||
border-radius: 8px;
|
||||
background: #C0C0C0;
|
||||
}
|
||||
.Table {
|
||||
display: table;
|
||||
margin: 2px;
|
||||
}
|
||||
.Row {
|
||||
display: table-row;
|
||||
}
|
||||
.Cell {
|
||||
display: table-cell;
|
||||
}
|
||||
.Color {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin: 2px;
|
||||
}
|
||||
.Circle {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 8px;
|
||||
-webkit-border-radius: 8px;
|
||||
-moz-border-radius: 8px;
|
||||
border-radius: 8px;
|
||||
background: #333;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>LED Matrix</h1>
|
||||
<div class="Table">
|
||||
<div class="Row">
|
||||
<div class="Cell">
|
||||
Color: <input type="text" id="colorText" size="10" value="#FFF" disabled>
|
||||
<div id="colorPicker" class="Table"></div>
|
||||
</div>
|
||||
<div class="Cell">
|
||||
<button id="btnSend">Send dots color to ESP-MINTIA</button>
|
||||
<div id="ledMatrix" class="Table"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="dataOutput"></div>
|
||||
<div id="txtResponse"></div>
|
||||
<script>
|
||||
var w = 10;
|
||||
var h = 6;
|
||||
var colorMin = 3;
|
||||
var colorMax = 15;
|
||||
var xhr;
|
||||
|
||||
function getRGB(e) {
|
||||
return window.getComputedStyle(e).backgroundColor.match(/\d+/g).map(function(a){ return Math.round(parseInt(a, 10) / 16.5); });
|
||||
}
|
||||
|
||||
function getColor(e) {
|
||||
var ct = document.getElementById("colorText");
|
||||
var rgb = getRGB(e);
|
||||
ct.value = "#" + rgb[0].toString(16) + rgb[1].toString(16) + rgb[2].toString(16);
|
||||
ct.style.backgroundColor = ct.value;
|
||||
}
|
||||
|
||||
function setColor(e) {
|
||||
var ct = document.getElementById("colorText");
|
||||
e.style.backgroundColor = ct.value;
|
||||
sendData(e);
|
||||
}
|
||||
|
||||
function sendData() {
|
||||
var o = document.getElementById("dataOutput");
|
||||
var text = "";
|
||||
for (var i = 0; i < (h * w); i++) {
|
||||
var d = document.getElementById("dot_" + i);
|
||||
var rgb = getRGB(d);
|
||||
text += String.fromCharCode(rgb[1] - colorMin);
|
||||
text += String.fromCharCode(rgb[0] - colorMin);
|
||||
text += String.fromCharCode(rgb[2] - colorMin);
|
||||
}
|
||||
text = "data=" + escape(text)
|
||||
o.innerHTML = text;
|
||||
if (!xhr) xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "led-matrix.lc", true);
|
||||
xhr.onreadystatechange=function() {
|
||||
if (xhr.readyState === 4) {
|
||||
var r = document.getElementById("txtResponse");
|
||||
r.innerHTML = xhr.responseText;
|
||||
}
|
||||
}
|
||||
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
xhr.send(text);
|
||||
}
|
||||
|
||||
var cp = document.getElementById("colorPicker");
|
||||
var colorHtml = "";
|
||||
var i = 0;
|
||||
for (var r = colorMin; r <= colorMax; r+=6) {
|
||||
for (var g = colorMin; g <= colorMax; g+=6) {
|
||||
if ((g % 6) == 3) colorHtml += '<div calss="Row">';
|
||||
for (var b = colorMin; b <= colorMax; b+=2) {
|
||||
i++;
|
||||
colorHtml += '<div class="Cell"><div class="Color" id="color' + i + '" style="background:#' + r.toString(16) + g.toString(16) + b.toString(16) + ';"></div></div>';
|
||||
}
|
||||
if ((g % 6) == 3) colorHtml += '</div>';
|
||||
}
|
||||
}
|
||||
cp.innerHTML = colorHtml;
|
||||
for (var j = 1; j <= i; j++) {
|
||||
var c = document.getElementById("color" + j);
|
||||
c.addEventListener("click", function(e) {
|
||||
getColor(e.target||e.srcElement);
|
||||
});
|
||||
}
|
||||
|
||||
var lm = document.getElementById("ledMatrix");
|
||||
var dotHtml = "";
|
||||
for (var i = 0; i < (h * w); i++) {
|
||||
if ((i % w) == 0) dotHtml += '<div calss="Row">';
|
||||
dotHtml += '<div class="Cell"><div class="Circle" id="dot_' + i + '"></div></div>';
|
||||
if ((i % w) == (w - 1)) dotHtml += '</div>';
|
||||
}
|
||||
lm.innerHTML = dotHtml;
|
||||
for (var i = 0; i < (h * w); i++) {
|
||||
var d = document.getElementById("dot_" + i);
|
||||
d.addEventListener("click", function(e) {
|
||||
setColor(e.target||e.srcElement);
|
||||
});
|
||||
}
|
||||
|
||||
document.getElementById("btnSend").addEventListener("click", sendData);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
12
Websocket/nodemcu-webide/bin/led-matrix.lua
Executable file
12
Websocket/nodemcu-webide/bin/led-matrix.lua
Executable file
@@ -0,0 +1,12 @@
|
||||
return function (connection, req, args)
|
||||
dofile('httpserver-header.lc')(connection, 200, 'html')
|
||||
|
||||
if req.method == 'POST' then
|
||||
local rd = req.getRequestData()
|
||||
if (rd['data'] ~= nil) then
|
||||
print("data: ",rd['data'])
|
||||
ws2812.write(rd['data'])
|
||||
end
|
||||
end
|
||||
collectgarbage()
|
||||
end
|
||||
115
Websocket/nodemcu-webide/bin/led-stick.html
Executable file
115
Websocket/nodemcu-webide/bin/led-stick.html
Executable file
@@ -0,0 +1,115 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>LED Cheering Stick</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>LED Cheering Stick</h1>
|
||||
<p>Text: <input type="text" id="myText" value="Hello!"><button id='set'>Set</button></p>
|
||||
<canvas id="myCanvas" width="140" height="28" style="border:1px solid #00f;">Your browser does not support the HTML5 canvas tag.</canvas>
|
||||
<div id="localStatus"></div>
|
||||
<div id="remoteStatus"></div>
|
||||
<script>
|
||||
var w = 140;
|
||||
var h = 28;
|
||||
var blockSize = 320;
|
||||
|
||||
var savingText;
|
||||
var savingFileOffset;
|
||||
var savingXhr;
|
||||
|
||||
function color_text(v) {
|
||||
return String.fromCharCode(Math.round(v/64));
|
||||
}
|
||||
|
||||
function setLocalStatus(msg) {
|
||||
document.getElementById("localStatus").innerHTML = msg;
|
||||
}
|
||||
|
||||
function setRemoteStatus(msg) {
|
||||
document.getElementById("remoteStatus").innerHTML = msg;
|
||||
}
|
||||
|
||||
function isXhrSuccess(xhr) {
|
||||
return ((xhr.readyState === 4) && (xhr.status == 200));
|
||||
}
|
||||
|
||||
function handleSaveCallback() {
|
||||
if (isXhrSuccess(savingXhr)) {
|
||||
setRemoteStatus("");
|
||||
|
||||
savingFileOffset += blockSize;
|
||||
if (savingFileOffset < savingText.length) {
|
||||
var params = "action=append&filename=led-stick.dat&data=" + encodeURIComponent(savingText.substring(savingFileOffset, savingFileOffset + blockSize));
|
||||
savingXhr = new XMLHttpRequest();
|
||||
savingXhr.open("POST", "file-api.lc", true);
|
||||
savingXhr.onreadystatechange = handleSaveCallback;
|
||||
savingXhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
setLocalStatus("Sending data: " + savingFileOffset + "/" + savingText.length + " bytes");
|
||||
savingXhr.send(params);
|
||||
} else {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "led-stick.lc", true);
|
||||
xhr.onreadystatechange = function() {
|
||||
if (isXhrSuccess(xhr)) {
|
||||
setLocalStatus("Run led-stick.lc!");
|
||||
}
|
||||
setRemoteStatus(xhr.responseText);
|
||||
};
|
||||
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
setLocalStatus("Data sent!");
|
||||
xhr.send();
|
||||
}
|
||||
} else {
|
||||
setRemoteStatus(savingXhr.responseText);
|
||||
}
|
||||
}
|
||||
|
||||
function save() {
|
||||
savingFileOffset = 0;
|
||||
var params = "action=save&filename=led-stick.dat&data=" + encodeURIComponent(savingText.substring(savingFileOffset, savingFileOffset + blockSize));
|
||||
savingXhr = new XMLHttpRequest();
|
||||
savingXhr.open("POST", "file-api.lc", true);
|
||||
savingXhr.onreadystatechange = handleSaveCallback;
|
||||
savingXhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
setLocalStatus("Sending data: " + savingFileOffset + "/" + savingText.length + " bytes");
|
||||
savingXhr.send(params);
|
||||
}
|
||||
|
||||
document.getElementById("set").addEventListener("click", function () {
|
||||
var t = document.getElementById("myText");
|
||||
var c = document.getElementById("myCanvas");
|
||||
var ctx = c.getContext("2d");
|
||||
var gradient = ctx.createLinearGradient(0, 0, c.width, 0);
|
||||
gradient.addColorStop("0", "red");
|
||||
gradient.addColorStop("0.5", "green");
|
||||
gradient.addColorStop("1.0", "purple");
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.rect(0, 0, w, h);
|
||||
// Fill with gradient
|
||||
ctx.fillStyle = gradient;
|
||||
// ctx.fillStyle = "black";
|
||||
ctx.fill();
|
||||
ctx.font = "bolder 24px sans-serif";
|
||||
// ctx.fillStyle = gradient;
|
||||
ctx.fillStyle = "white";
|
||||
ctx.fillText(t.value, 0, 22);
|
||||
|
||||
var d = ctx.getImageData(0, 0, w, h);
|
||||
savingText = "";
|
||||
for (var x = 0; x < w; x++)
|
||||
{
|
||||
for (var y = (h - 1); y >= 0; y--)
|
||||
{
|
||||
savingText += color_text(d.data[((x + y * w) * 4) + 1]); // Green
|
||||
savingText += color_text(d.data[((x + y * w) * 4) + 0]); // Red
|
||||
savingText += color_text(d.data[((x + y * w) * 4) + 2]); // Blue
|
||||
}
|
||||
}
|
||||
save();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
31
Websocket/nodemcu-webide/bin/led-stick.lua
Executable file
31
Websocket/nodemcu-webide/bin/led-stick.lua
Executable file
@@ -0,0 +1,31 @@
|
||||
return function (connection, req, args)
|
||||
local pin, w, h, offset = 1, 140, 28, 0
|
||||
|
||||
if connection ~= nil then
|
||||
dofile('httpserver-header.lc')(connection, 200, 'html')
|
||||
end
|
||||
|
||||
gpio.mode(pin, gpio.INT)
|
||||
local function pin1cb(level)
|
||||
print(level)
|
||||
file.open('led-stick.dat', 'r')
|
||||
if level == 1 then
|
||||
offset = 0
|
||||
while offset < w do
|
||||
file.seek("set", (offset * h) * 3)
|
||||
ws2812.write(file.read(h * 3))
|
||||
offset = offset + 1
|
||||
end
|
||||
else
|
||||
offset = w - 1
|
||||
while offset >= 0 do
|
||||
file.seek("set", (offset * h) * 3)
|
||||
ws2812.write(file.read(h * 3))
|
||||
offset = offset - 1
|
||||
end
|
||||
end
|
||||
file.close()
|
||||
ws2812.write(string.char(0):rep(h * 3))
|
||||
end
|
||||
gpio.trig(pin, 'both', pin1cb)
|
||||
end
|
||||
63
Websocket/nodemcu-webide/bin/led-text.html
Executable file
63
Websocket/nodemcu-webide/bin/led-text.html
Executable file
@@ -0,0 +1,63 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>LED Text</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>LED Text</h1>
|
||||
<p>Text: <input type="text" id="myText" value="Hello World!"><button id='set'>Set</button></p>
|
||||
<canvas id="myCanvas" width="72" height="12" style="border:1px solid #00f;">Your browser does not support the HTML5 canvas tag.</canvas>
|
||||
<div id="dataOutput"></div>
|
||||
<script>
|
||||
var w = 72;
|
||||
var h = 12;
|
||||
|
||||
function color_text(v) {
|
||||
return String.fromCharCode(Math.round(v/64));
|
||||
}
|
||||
|
||||
document.getElementById("set").addEventListener("click", function () {
|
||||
var t = document.getElementById("myText");
|
||||
var c = document.getElementById("myCanvas");
|
||||
var ctx = c.getContext("2d");
|
||||
ctx.beginPath();
|
||||
ctx.rect(0, 0, w, h);
|
||||
ctx.fillStyle = "black";
|
||||
ctx.fill();
|
||||
ctx.font = "bolder 12px sans-serif";
|
||||
var gradient=ctx.createLinearGradient(0,0,c.width,0);
|
||||
gradient.addColorStop("0","orange");
|
||||
gradient.addColorStop("0.5","red");
|
||||
gradient.addColorStop("1.0","purple");
|
||||
// Fill with gradient
|
||||
ctx.fillStyle=gradient;
|
||||
ctx.fillText(t.value, 0, 9);
|
||||
|
||||
var d = ctx.getImageData(0,0,w,h);
|
||||
var o = document.getElementById("dataOutput");
|
||||
text = "";
|
||||
for (var y=0;y<h;y+=2)
|
||||
{
|
||||
for (var x=0;x<w;x+=2)
|
||||
{
|
||||
//average 4 pixels colors
|
||||
//text += escape_color((d.data[((x+y*w)*4)+1] + d.data[((x+1+y*w)*4)+1] + d.data[((x+(y+1)*w)*4)+1] + d.data[((x+1+(y+1)*w)*4)+1]) / 4); // green
|
||||
//text += escape_color((d.data[((x+y*w)*4)+0] + d.data[((x+1+y*w)*4)+0] + d.data[((x+(y+1)*w)*4)+0] + d.data[((x+1+(y+1)*w)*4)+0]) / 4); // red
|
||||
//text += escape_color((d.data[((x+y*w)*4)+2] + d.data[((x+1+y*w)*4)+2] + d.data[((x+(y+1)*w)*4)+2] + d.data[((x+1+(y+1)*w)*4)+2]) / 4); // blue
|
||||
text += color_text(d.data[((x+y*w)*4)+1]); // Green
|
||||
text += color_text(d.data[((x+y*w)*4)+0]); // Red
|
||||
text += color_text(d.data[((x+y*w)*4)+2]); // Blue
|
||||
}
|
||||
}
|
||||
text = "data=" + escape(text);
|
||||
o.innerHTML = text;
|
||||
xhr=new XMLHttpRequest();
|
||||
xhr.open("POST", "led-text.lc", true);
|
||||
xhr.onreadystatechange=function() {}
|
||||
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||
xhr.send(text);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
46
Websocket/nodemcu-webide/bin/led-text.lua
Executable file
46
Websocket/nodemcu-webide/bin/led-text.lua
Executable file
@@ -0,0 +1,46 @@
|
||||
return function (connection, req, args)
|
||||
dofile('httpserver-header.lc')(connection, 200, 'html')
|
||||
|
||||
local w, h, dataWidth, offset = 10, 6, 36, 0
|
||||
-- timer id(0-6), interval in ms
|
||||
local tmrId, tmrMs = 4, 200
|
||||
|
||||
if req.method == 'POST' then
|
||||
local rd = req.getRequestData()
|
||||
if (rd['data'] ~= nil) then
|
||||
file.open('led-text.dat', 'w+')
|
||||
file.write(rd['data'])
|
||||
file.close()
|
||||
end
|
||||
end
|
||||
collectgarbage()
|
||||
|
||||
tmr.alarm(tmrId, tmrMs, tmr.ALARM_SEMI, function()
|
||||
if offset < dataWidth then
|
||||
local data = ''
|
||||
file.open('led-text.dat', 'r')
|
||||
local row = 0
|
||||
while row < h do
|
||||
file.seek("set", (row * dataWidth + offset) * 3)
|
||||
local size = w
|
||||
if (offset + w > dataWidth) then
|
||||
size = dataWidth - offset
|
||||
end
|
||||
|
||||
data = data .. file.read(size * 3)
|
||||
if size < w then
|
||||
data = data .. string.char(0):rep((w - size) * 3)
|
||||
end
|
||||
row = row + 1
|
||||
end
|
||||
file.close()
|
||||
ws2812.write(data)
|
||||
|
||||
offset = offset + 1
|
||||
tmr.start(tmrId)
|
||||
else
|
||||
ws2812.write(string.char(0):rep(w*h*3))
|
||||
tmr.unregister(tmrId)
|
||||
end
|
||||
end)
|
||||
end
|
||||
BIN
Websocket/nodemcu-webide/bin/modes.js.gz
Executable file
BIN
Websocket/nodemcu-webide/bin/modes.js.gz
Executable file
Binary file not shown.
79
Websocket/nodemcu-webide/bin/robot.lua
Executable file
79
Websocket/nodemcu-webide/bin/robot.lua
Executable file
@@ -0,0 +1,79 @@
|
||||
return function (connection, req, args)
|
||||
dofile('httpserver-header.lc')(connection, 200, 'html')
|
||||
|
||||
--define robot dance steps
|
||||
--F=move forward, B=move backward, L=turn left, R=turn right, S=stop
|
||||
local steps = 'FFSSFFRSRFFSFFSSBBSSBBSSBBSSBBSSFFSSFFSSFFSSFFLSLBBS' --Tango
|
||||
local curStepIdx = 1
|
||||
|
||||
--1=GPIO5, 2=GPIO4, 3=GPIO0, 4=GPIO2, 5=GPIO14, 6=GPIO12,
|
||||
--7=GPIO13, 8=GPIO15, 9=GPIO3, 10=GPIO1, 11=GPIO9, 12=GPIO10
|
||||
local leftpwm, leftduty, leftpin1, leftpin2 = 1, 818, 2, 4 --GPIO5, 80%, GPIO4, GPIO2
|
||||
local rightpwm,rightduty, rightpin1, rightpin2 = 5, 717, 6, 7 --GPIO14, 70%, GPIO12, GPIO13
|
||||
-- timer id(0-6), interval in ms
|
||||
local tmrId, tmrMs = 4, 800
|
||||
|
||||
-- init motors
|
||||
pwm.setup(leftpwm, 500, leftduty)
|
||||
pwm.start(leftpwm)
|
||||
gpio.mode(leftpin1, gpio.OUTPUT)
|
||||
gpio.mode(leftpin2, gpio.OUTPUT)
|
||||
pwm.setup(rightpwm, 500, rightduty)
|
||||
pwm.start(rightpwm)
|
||||
gpio.mode(rightpin1, gpio.OUTPUT)
|
||||
gpio.mode(rightpin2, gpio.OUTPUT)
|
||||
|
||||
--run step every tmrMs
|
||||
tmr.alarm(tmrId, tmrMs, tmr.ALARM_SEMI, function()
|
||||
local curStep = string.sub(steps, curStepIdx, curStepIdx)
|
||||
if ((curStep ~= nil) and (curStep ~= '')) then
|
||||
if (curStep == 'F') then
|
||||
gpio.write(leftpin1, gpio.LOW)
|
||||
gpio.write(leftpin2, gpio.HIGH)
|
||||
gpio.write(rightpin1, gpio.LOW)
|
||||
gpio.write(rightpin2, gpio.HIGH)
|
||||
elseif (curStep == 'B') then
|
||||
gpio.write(leftpin1, gpio.HIGH)
|
||||
gpio.write(leftpin2, gpio.LOW)
|
||||
gpio.write(rightpin1, gpio.HIGH)
|
||||
gpio.write(rightpin2, gpio.LOW)
|
||||
elseif (curStep == 'L') then
|
||||
gpio.write(leftpin1, gpio.LOW)
|
||||
gpio.write(leftpin2, gpio.HIGH)
|
||||
gpio.write(rightpin1, gpio.HIGH)
|
||||
gpio.write(rightpin2, gpio.LOW)
|
||||
elseif (curStep == 'R') then
|
||||
gpio.write(leftpin1, gpio.HIGH)
|
||||
gpio.write(leftpin2, gpio.LOW)
|
||||
gpio.write(rightpin1, gpio.LOW)
|
||||
gpio.write(rightpin2, gpio.HIGH)
|
||||
elseif (curStep == 'S') then
|
||||
gpio.write(leftpin1, gpio.LOW)
|
||||
gpio.write(leftpin2, gpio.LOW)
|
||||
gpio.write(rightpin1, gpio.LOW)
|
||||
gpio.write(rightpin2, gpio.LOW)
|
||||
end
|
||||
curStepIdx = curStepIdx + 1
|
||||
tmr.start(tmrId)
|
||||
else
|
||||
pwm.stop(leftpwm)
|
||||
gpio.write(leftpin1, gpio.LOW)
|
||||
gpio.write(leftpin2, gpio.LOW)
|
||||
pwm.stop(rightpwm)
|
||||
gpio.write(rightpin1, gpio.LOW)
|
||||
gpio.write(rightpin2, gpio.LOW)
|
||||
tmr.unregister(tmrId)
|
||||
end
|
||||
end)
|
||||
|
||||
connection:send([===[<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>robot.lua</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Running!</h1>
|
||||
</body>
|
||||
</html>]===])
|
||||
end
|
||||
92
Websocket/nodemcu-webide/bin/system-info.lua
Executable file
92
Websocket/nodemcu-webide/bin/system-info.lua
Executable file
@@ -0,0 +1,92 @@
|
||||
return function (connection, req, args)
|
||||
dofile('httpserver-header.lc')(connection, 200, 'html')
|
||||
|
||||
connection:send('<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>System Info</title></head><body>')
|
||||
|
||||
connection:send('<p><b>Chip ID:</b> '..node.chipid()..'</p>')
|
||||
connection:send('<p><b>Flash ID:</b> '..node.flashid()..'</p>')
|
||||
connection:send('<p><b>Heap:</b> '..node.heap()..'</p>')
|
||||
connection:send('<p><b>Info:</b> '..node.info()..'</p>')
|
||||
|
||||
connection:send('<p><b>Vdd:</b> '..adc.readvdd33()..' mV</p>')
|
||||
|
||||
local address, size = file.fscfg()
|
||||
connection:send('<p><b>File System Address:</b> '..address..'</p>')
|
||||
connection:send('<p><b>File System Size:</b> '..size..' bytes</p>')
|
||||
|
||||
local tm = rtctime.epoch2cal(rtctime.get())
|
||||
connection:send('<p><b>RTC Time:</b> '..string.format("%04d/%02d/%02d %02d:%02d:%02d", tm["year"], tm["mon"], tm["day"], tm["hour"], tm["min"], tm["sec"])..'</p>')
|
||||
|
||||
local remaining, used, total = file.fsinfo()
|
||||
connection:send('<p><b>File System Usage:</b> '..used..' / '..total..' bytes</p>')
|
||||
|
||||
connection:send('<p><b>Wifi STA MAC Address:</b> '..wifi.sta.getmac()..'</p>')
|
||||
connection:send('<p><b>Wifi AP MAC Address:</b> '..wifi.ap.getmac()..'</p>')
|
||||
|
||||
connection:send('<p><b>WiFi Channel:</b> '..wifi.getchannel()..'</p>')
|
||||
|
||||
local wifimode = wifi.getmode()
|
||||
if wifimode == wifi.STATION then
|
||||
connection:send('<p><b>WiFi Mode:</b> STATION</p>')
|
||||
elseif wifimode == wifi.SOFTAP then
|
||||
connection:send('<p><b>WiFi Mode:</b> SOFTAP</p>')
|
||||
elseif wifimode == wifi.STATIONAP then
|
||||
connection:send('<p><b>WiFi Mode:</b> STATIONAP</p>')
|
||||
elseif wifimode == wifi.NULLMODE then
|
||||
connection:send('<p><b>WiFi Mode:</b> NULLMODE</p>')
|
||||
end
|
||||
|
||||
if (wifimode == wifi.STATIONAP) or (wifimode == wifi.SOFTAP) then
|
||||
local ip, netmask, gateway = wifi.ap.getip()
|
||||
connection:send('<p><b>AP IP:</b> '..ip..'</p>')
|
||||
connection:send('<p><b>AP netmask:</b> '..netmask..'</p>')
|
||||
connection:send('<p><b>AP gateway:</b> '..gateway..'</p>')
|
||||
|
||||
connection:send('<p><b>AP client list:</b> ')
|
||||
local clients = wifi.ap.getclient()
|
||||
for mac, ip in pairs(clients) do
|
||||
connection:send('<p><b>'..mac..':</b> '..ip..'</p>')
|
||||
end
|
||||
connection:send('</p>')
|
||||
end
|
||||
|
||||
local wifiphymode = wifi.getphymode()
|
||||
if wifiphymode == wifi.PHYMODE_B then
|
||||
connection:send('<p><b>WiFi Physical Mode:</b> B</p>')
|
||||
elseif wifiphymode == wifi.PHYMODE_G then
|
||||
connection:send('<p><b>WiFi Physical Mode:</b> G</p>')
|
||||
elseif wifiphymode == wifi.PHYMODE_N then
|
||||
connection:send('<p><b>WiFi Physical Mode:</b> N</p>')
|
||||
end
|
||||
|
||||
local status = wifi.sta.status()
|
||||
if status == wifi.STA_IDLE then
|
||||
connection:send('<p><b>wifi.sta.status:</b> STA_IDLE</p>')
|
||||
elseif status == wifi.STA_CONNECTING then
|
||||
connection:send('<p><b>wifi.sta.status:</b> STA_CONNECTING</p>')
|
||||
elseif status == wifi.STA_WRONGPWD then
|
||||
connection:send('<p><b>wifi.sta.status:</b> STA_WRONGPWD</p>')
|
||||
elseif status == wifi.STA_APNOTFOUND then
|
||||
connection:send('<p><b>wifi.sta.status:</b> STA_APNOTFOUND</p>')
|
||||
elseif status == wifi.STA_FAIL then
|
||||
connection:send('<p><b>wifi.sta.status:</b> STA_FAIL</p>')
|
||||
elseif status == wifi.STA_GOTIP then
|
||||
connection:send('<p><b>wifi.sta.status:</b> STA_GOTIP</p>')
|
||||
connection:send('<p><b>Hostname:</b> '..wifi.sta.gethostname()..'</p>')
|
||||
|
||||
local ip, netmask, gateway = wifi.sta.getip()
|
||||
connection:send('<p><b>STA IP:</b> '..ip..'</p>')
|
||||
connection:send('<p><b>STA netmask:</b> '..netmask..'</p>')
|
||||
connection:send('<p><b>STA gateway:</b> '..gateway..'</p>')
|
||||
|
||||
local ssid, password, bssid_set, bssid = wifi.sta.getconfig()
|
||||
connection:send('<p><b>SSID:</b> '..ssid..'</p>')
|
||||
-- connection:send('<p><b>password:</b> '..password..'</p>') -- not sure if it should be shown.
|
||||
connection:send('<p><b>BSSID set:</b> '..bssid_set..'</p>')
|
||||
connection:send('<p><b>BSSID:</b> '..bssid..'</p>')
|
||||
|
||||
connection:send('<p><b>STA Broadcast IP:</b> '..wifi.sta.getbroadcast()..'</p>')
|
||||
connection:send('<p><b>RSSI:</b> '..wifi.sta.getrssi()..' dB</p>')
|
||||
end
|
||||
connection:send('</body></html>')
|
||||
end
|
||||
44
Websocket/nodemcu-webide/bin/ws-echo.html
Executable file
44
Websocket/nodemcu-webide/bin/ws-echo.html
Executable file
@@ -0,0 +1,44 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>WebSocket Echo</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>WebSocket Echo</h1>
|
||||
<p>Message: <input type="text" id="message"> <button onclick="sendMessage()">Send</button></p>
|
||||
|
||||
<div id="log"></div>
|
||||
|
||||
<script language="javascript" type="text/javascript">
|
||||
var wsUri = "ws://" + location.hostname + "/ws-echo.lc";
|
||||
var messageLog;
|
||||
|
||||
function init()
|
||||
{
|
||||
logDiv = document.getElementById("log");
|
||||
websocket = new WebSocket(wsUri);
|
||||
websocket.onopen = function(evt) { appendLog('<span style="color: green;">CONNECTED</span>') };
|
||||
websocket.onclose = function(evt) { appendLog('<span style="color: green;">DISCONNECTED</span>') };
|
||||
websocket.onmessage = function(evt) { appendLog('<span style="color: blue;">RESPONSE:</span> ' + evt.data) };
|
||||
websocket.onerror = function(evt) { appendLog('<span style="color: red;">ERROR:</span> ' + evt.data) };
|
||||
}
|
||||
|
||||
function sendMessage()
|
||||
{
|
||||
message = document.getElementById("message").value;
|
||||
appendLog('<span style="color: green;">SENT:</span> ' + message);
|
||||
websocket.send(message);
|
||||
}
|
||||
|
||||
function appendLog(log)
|
||||
{
|
||||
var pre = document.createElement("p");
|
||||
pre.innerHTML = log;
|
||||
logDiv.appendChild(pre);
|
||||
}
|
||||
|
||||
window.addEventListener("load", init, false);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
5
Websocket/nodemcu-webide/bin/ws-echo.lua
Executable file
5
Websocket/nodemcu-webide/bin/ws-echo.lua
Executable file
@@ -0,0 +1,5 @@
|
||||
return function (socket)
|
||||
function socket.onmessage(payload, opcode)
|
||||
socket.send(payload, opcode)
|
||||
end
|
||||
end
|
||||
160
Websocket/nodemcu-webide/bin/ws-led.html
Executable file
160
Websocket/nodemcu-webide/bin/ws-led.html
Executable file
@@ -0,0 +1,160 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=0.67">
|
||||
<title>WebSocket LED Matrix</title>
|
||||
<style>
|
||||
#colorPicker {
|
||||
padding: 4px;
|
||||
background: #000;
|
||||
}
|
||||
#ledMatrix {
|
||||
width: 320px;
|
||||
height: 192px;
|
||||
padding: 16px;
|
||||
-webkit-border-radius:8px;
|
||||
-moz-border-radius: 8px;
|
||||
border-radius: 8px;
|
||||
background: #C0C0C0;
|
||||
}
|
||||
.Table {
|
||||
display: table;
|
||||
margin: 2px;
|
||||
}
|
||||
.Row {
|
||||
display: table-row;
|
||||
}
|
||||
.Cell {
|
||||
display: table-cell;
|
||||
}
|
||||
.Color {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin: 2px;
|
||||
}
|
||||
.Circle {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 8px;
|
||||
-webkit-border-radius: 8px;
|
||||
-moz-border-radius: 8px;
|
||||
border-radius: 8px;
|
||||
background: #333;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>WebSocket LED Matrix</h1>
|
||||
<div class="Table">
|
||||
<div class="Row">
|
||||
<div class="Cell">
|
||||
Color: <input type="text" id="colorText" size="10" value="#FFF" disabled>
|
||||
<div id="colorPicker" class="Table"></div>
|
||||
</div>
|
||||
<div class="Cell">
|
||||
<button id="btnSend">Send dots color to ESP-MINTIA</button>
|
||||
<div id="ledMatrix" class="Table"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="dataOutput"></div>
|
||||
<div id="txtResponse"></div>
|
||||
<script>
|
||||
var w = 10;
|
||||
var h = 6;
|
||||
var colorMin = 3;
|
||||
var colorMax = 15;
|
||||
var wsUri = "ws://" + location.hostname + "/ws-led.lc";
|
||||
var websocket;
|
||||
var wsReady = false;
|
||||
|
||||
function getRGB(e) {
|
||||
return window.getComputedStyle(e).backgroundColor.match(/\d+/g).map(function(a){ return Math.round(parseInt(a, 10) / 16.5); });
|
||||
}
|
||||
|
||||
function getColor(e) {
|
||||
var ct = document.getElementById("colorText");
|
||||
var rgb = getRGB(e);
|
||||
ct.value = "#" + rgb[0].toString(16) + rgb[1].toString(16) + rgb[2].toString(16);
|
||||
ct.style.backgroundColor = ct.value;
|
||||
}
|
||||
|
||||
function setColor(e) {
|
||||
var ct = document.getElementById("colorText");
|
||||
e.style.backgroundColor = ct.value;
|
||||
sendData(e);
|
||||
}
|
||||
|
||||
function initWebSocket() {
|
||||
websocket = new WebSocket(wsUri);
|
||||
websocket.onopen = function(evt) { wsReady = true; };
|
||||
websocket.onclose = function(evt) { websocket = null; wsReady = false; };
|
||||
websocket.onmessage = function(evt) { var o = document.getElementById("dataOutput"); o.innerHTML = evt.data; };
|
||||
websocket.onerror = function(evt) { var o = document.getElementById("dataOutput"); o.innerHTML = evt.data; websocket = null; wsReady = false; };
|
||||
}
|
||||
|
||||
function sendData() {
|
||||
var text = "";
|
||||
for (var i = 0; i < (h * w); i++) {
|
||||
var d = document.getElementById("dot_" + i);
|
||||
var rgb = getRGB(d);
|
||||
text += String.fromCharCode(rgb[1] - colorMin);
|
||||
text += String.fromCharCode(rgb[0] - colorMin);
|
||||
text += String.fromCharCode(rgb[2] - colorMin);
|
||||
}
|
||||
if (!websocket) {
|
||||
initWebSocket();
|
||||
}
|
||||
if (wsReady) {
|
||||
websocket.send(text, { binary: true });
|
||||
}
|
||||
}
|
||||
|
||||
function initColorPicker() {
|
||||
var cp = document.getElementById("colorPicker");
|
||||
var colorHtml = "";
|
||||
var i = 0;
|
||||
for (var r = colorMin; r <= colorMax; r+=6) {
|
||||
for (var g = colorMin; g <= colorMax; g+=6) {
|
||||
if ((g % 6) == 3) colorHtml += '<div calss="Row">';
|
||||
for (var b = colorMin; b <= colorMax; b+=2) {
|
||||
i++;
|
||||
colorHtml += '<div class="Cell"><div class="Color" id="color' + i + '" style="background:#' + r.toString(16) + g.toString(16) + b.toString(16) + ';"></div></div>';
|
||||
}
|
||||
if ((g % 6) == 3) colorHtml += '</div>';
|
||||
}
|
||||
}
|
||||
cp.innerHTML = colorHtml;
|
||||
for (var j = 1; j <= i; j++) {
|
||||
var c = document.getElementById("color" + j);
|
||||
c.addEventListener("click", function(e) {
|
||||
getColor(e.target||e.srcElement);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function initLedMatrix() {
|
||||
var lm = document.getElementById("ledMatrix");
|
||||
var dotHtml = "";
|
||||
for (var i = 0; i < (h * w); i++) {
|
||||
if ((i % w) == 0) dotHtml += '<div calss="Row">';
|
||||
dotHtml += '<div class="Cell"><div class="Circle" id="dot_' + i + '"></div></div>';
|
||||
if ((i % w) == (w - 1)) dotHtml += '</div>';
|
||||
}
|
||||
lm.innerHTML = dotHtml;
|
||||
for (var i = 0; i < (h * w); i++) {
|
||||
var d = document.getElementById("dot_" + i);
|
||||
d.addEventListener("click", function(e) {
|
||||
setColor(e.target||e.srcElement);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
initWebSocket();
|
||||
initColorPicker();
|
||||
initLedMatrix();
|
||||
document.getElementById("btnSend").addEventListener("click", sendData);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
5
Websocket/nodemcu-webide/bin/ws-led.lua
Executable file
5
Websocket/nodemcu-webide/bin/ws-led.lua
Executable file
@@ -0,0 +1,5 @@
|
||||
return function (socket)
|
||||
function socket.onmessage(payload, opcode)
|
||||
ws2812.write(payload)
|
||||
end
|
||||
end
|
||||
83
Websocket/nodemcu-webide/bin/ws-robot.html
Executable file
83
Websocket/nodemcu-webide/bin/ws-robot.html
Executable file
@@ -0,0 +1,83 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>WebSocket Remote Robot</title>
|
||||
<style>
|
||||
canvas {
|
||||
border: 1px solid #000000;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>WebSocket Remote Robot</h1>
|
||||
<p>Touch the canvas to control the robot.</p>
|
||||
<canvas id="canvas" width="400" height="400"></canvas>
|
||||
<script language="javascript" type="text/javascript">
|
||||
var wsUri = "ws://" + location.hostname + "/ws-robot.lc";
|
||||
var websocket;
|
||||
var canvas, context;
|
||||
|
||||
function init() {
|
||||
websocket = new WebSocket(wsUri);
|
||||
websocket.onopen = function(evt) { };
|
||||
websocket.onclose = function(evt) { };
|
||||
websocket.onmessage = function(evt) { };
|
||||
websocket.onerror = function(evt) { };
|
||||
|
||||
canvas = document.getElementById('canvas');
|
||||
context = canvas.getContext("2d");
|
||||
|
||||
// Add mouse event listeners to canvas element
|
||||
canvas.addEventListener("mousedown", press, false);
|
||||
canvas.addEventListener("mousemove", drag, false);
|
||||
canvas.addEventListener("mouseup", release);
|
||||
canvas.addEventListener("mouseout", cancel, false);
|
||||
|
||||
// Add touch event listeners to canvas element
|
||||
canvas.addEventListener("touchstart", press, false);
|
||||
canvas.addEventListener("touchmove", drag, false);
|
||||
canvas.addEventListener("touchend", release, false);
|
||||
canvas.addEventListener("touchcancel", cancel, false);
|
||||
}
|
||||
|
||||
function sendMessage(message) {
|
||||
websocket.send(message);
|
||||
}
|
||||
|
||||
function press(e) {
|
||||
var mouseX = (e.changedTouches ? e.changedTouches[0].pageX : e.pageX) - this.offsetLeft;
|
||||
var mouseY = (e.changedTouches ? e.changedTouches[0].pageY : e.pageY) - this.offsetTop;
|
||||
if (mouseX < 150) {
|
||||
sendMessage('L');
|
||||
} else if (mouseX > 250) {
|
||||
sendMessage('R');
|
||||
} else {
|
||||
sendMessage('F');
|
||||
}
|
||||
}
|
||||
|
||||
function drag(e) {
|
||||
var mouseX = (e.changedTouches ? e.changedTouches[0].pageX : e.pageX) - this.offsetLeft;
|
||||
var mouseY = (e.changedTouches ? e.changedTouches[0].pageY : e.pageY) - this.offsetTop;
|
||||
if (mouseX < 150) {
|
||||
sendMessage('L');
|
||||
} else if (mouseX > 250) {
|
||||
sendMessage('R');
|
||||
} else {
|
||||
sendMessage('F');
|
||||
}
|
||||
}
|
||||
|
||||
function release(e) {
|
||||
sendMessage('S');
|
||||
}
|
||||
|
||||
function cancel(e) {
|
||||
sendMessage('S');
|
||||
}
|
||||
|
||||
window.addEventListener("load", init, false);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
57
Websocket/nodemcu-webide/bin/ws-robot.lua
Executable file
57
Websocket/nodemcu-webide/bin/ws-robot.lua
Executable file
@@ -0,0 +1,57 @@
|
||||
return function (socket)
|
||||
--1=GPIO5, 2=GPIO4, 3=GPIO0, 4=GPIO2, 5=GPIO14, 6=GPIO12,
|
||||
--7=GPIO13, 8=GPIO15, 9=GPIO3, 10=GPIO1, 11=GPIO9, 12=GPIO10
|
||||
local leftpwm, leftduty, leftpin1, leftpin2 = 1, 818, 2, 4 --GPIO5, 80%, GPIO4, GPIO2
|
||||
local rightpwm,rightduty, rightpin1, rightpin2 = 5, 717, 6, 7 --GPIO14, 70%, GPIO12, GPIO13
|
||||
-- timer id(0-6), interval in ms
|
||||
local tmrId, tmrMs = 4, 800
|
||||
|
||||
-- init motors
|
||||
pwm.setup(leftpwm, 500, leftduty)
|
||||
pwm.start(leftpwm)
|
||||
gpio.mode(leftpin1, gpio.OUTPUT)
|
||||
gpio.mode(leftpin2, gpio.OUTPUT)
|
||||
pwm.setup(rightpwm, 500, rightduty)
|
||||
pwm.start(rightpwm)
|
||||
gpio.mode(rightpin1, gpio.OUTPUT)
|
||||
gpio.mode(rightpin2, gpio.OUTPUT)
|
||||
|
||||
function socket.onmessage(payload, opcode)
|
||||
curStep = payload:sub(1, 1)
|
||||
if (curStep == 'F') then
|
||||
gpio.write(leftpin1, gpio.LOW)
|
||||
gpio.write(leftpin2, gpio.HIGH)
|
||||
gpio.write(rightpin1, gpio.LOW)
|
||||
gpio.write(rightpin2, gpio.HIGH)
|
||||
elseif (curStep == 'B') then
|
||||
gpio.write(leftpin1, gpio.HIGH)
|
||||
gpio.write(leftpin2, gpio.LOW)
|
||||
gpio.write(rightpin1, gpio.HIGH)
|
||||
gpio.write(rightpin2, gpio.LOW)
|
||||
elseif (curStep == 'L') then
|
||||
gpio.write(leftpin1, gpio.LOW)
|
||||
gpio.write(leftpin2, gpio.HIGH)
|
||||
gpio.write(rightpin1, gpio.HIGH)
|
||||
gpio.write(rightpin2, gpio.LOW)
|
||||
elseif (curStep == 'R') then
|
||||
gpio.write(leftpin1, gpio.HIGH)
|
||||
gpio.write(leftpin2, gpio.LOW)
|
||||
gpio.write(rightpin1, gpio.LOW)
|
||||
gpio.write(rightpin2, gpio.HIGH)
|
||||
elseif (curStep == 'S') then
|
||||
gpio.write(leftpin1, gpio.LOW)
|
||||
gpio.write(leftpin2, gpio.LOW)
|
||||
gpio.write(rightpin1, gpio.LOW)
|
||||
gpio.write(rightpin2, gpio.LOW)
|
||||
end
|
||||
end
|
||||
|
||||
function socket.onclose()
|
||||
pwm.stop(leftpwm)
|
||||
gpio.write(leftpin1, gpio.LOW)
|
||||
gpio.write(leftpin2, gpio.LOW)
|
||||
pwm.stop(rightpwm)
|
||||
gpio.write(rightpin1, gpio.LOW)
|
||||
gpio.write(rightpin2, gpio.LOW)
|
||||
end
|
||||
end
|
||||
15
Websocket/nodemcu-webide/src/addons.js
Executable file
15
Websocket/nodemcu-webide/src/addons.js
Executable file
File diff suppressed because one or more lines are too long
13
Websocket/nodemcu-webide/src/codemirror.js
Executable file
13
Websocket/nodemcu-webide/src/codemirror.js
Executable file
File diff suppressed because one or more lines are too long
BIN
Websocket/nodemcu-webide/src/favicon.ico
Executable file
BIN
Websocket/nodemcu-webide/src/favicon.ico
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 7.2 KiB |
199
Websocket/nodemcu-webide/src/index.html
Executable file
199
Websocket/nodemcu-webide/src/index.html
Executable file
File diff suppressed because one or more lines are too long
283
Websocket/nodemcu-webide/src/index.js
Executable file
283
Websocket/nodemcu-webide/src/index.js
Executable file
@@ -0,0 +1,283 @@
|
||||
var blockSize = 1024;
|
||||
var normalColor = "#0067B0";
|
||||
var selectedColor = "#CCCCCC";
|
||||
var showInvisibles = false;
|
||||
var editor;
|
||||
var curFileItem;
|
||||
var savingText;
|
||||
var savingFilename;
|
||||
var savingFileOffset;
|
||||
var savingXhr;
|
||||
|
||||
function setLocalStatus(msg) {
|
||||
document.getElementById("localStatus").innerHTML = msg;
|
||||
}
|
||||
|
||||
function setRemoteStatus(msg) {
|
||||
document.getElementById("remoteStatus").innerHTML = msg;
|
||||
}
|
||||
|
||||
function loadScript(url, callback) {
|
||||
setLocalStatus("<span class=\"icon icon-loading\"></span> Loading " + url);
|
||||
|
||||
var script = document.createElement("script");
|
||||
script.type = "text/javascript";
|
||||
|
||||
if (script.readyState) { //IE
|
||||
script.onreadystatechange = function () {
|
||||
if (script.readyState == "loaded" || script.readyState == "complete") {
|
||||
script.onreadystatechange = null;
|
||||
callback();
|
||||
}
|
||||
};
|
||||
} else { //Others
|
||||
script.onload = function () {
|
||||
setLocalStatus("");
|
||||
|
||||
callback();
|
||||
};
|
||||
}
|
||||
|
||||
script.src = url;
|
||||
document.getElementsByTagName("head")[0].appendChild(script);
|
||||
}
|
||||
|
||||
function isXhrSuccess(xhr) {
|
||||
return ((xhr.readyState === 4) && (xhr.status == 200));
|
||||
}
|
||||
|
||||
function handleFileClick(item) {
|
||||
if (curFileItem) {
|
||||
curFileItem.classList.remove("selected");
|
||||
}
|
||||
item.classList.add("selected");
|
||||
curFileItem = item;
|
||||
|
||||
loadFile();
|
||||
}
|
||||
|
||||
function loadFilelist() {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "file-api.lc", true);
|
||||
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
xhr.onreadystatechange = function () {
|
||||
if (isXhrSuccess(xhr)) {
|
||||
//setRemoteStatus("");
|
||||
var filelistHtml = "";
|
||||
var json = JSON.parse(xhr.responseText);
|
||||
var files = new Array(json.length);
|
||||
var i = 0;
|
||||
for (var filename in json) {
|
||||
files[i++] = filename;
|
||||
}
|
||||
files.sort();
|
||||
for (i = 0; i < files.length; i++) {
|
||||
filelistHtml += '<div class="fileItem" id="' + files[i] + '"><span class="icon icon-file"></span> ' + files[i] + '</div>'
|
||||
}
|
||||
document.getElementById("filelist").innerHTML = filelistHtml;
|
||||
curFileItem = null;
|
||||
|
||||
fileItemList = document.getElementsByClassName("fileItem");
|
||||
for (i = 0; i < fileItemList.length; i++) {
|
||||
fileItemList[i].addEventListener("click", function (e) {
|
||||
handleFileClick(e.target||e.srcElement);
|
||||
});
|
||||
}
|
||||
|
||||
setLocalStatus("");
|
||||
} else {
|
||||
//setRemoteStatus(xhr.responseText);
|
||||
}
|
||||
};
|
||||
setLocalStatus("<span class=\"icon icon-loading\"></span> Loading file list");
|
||||
xhr.send("action=list");
|
||||
}
|
||||
|
||||
function handleSaveCallback() {
|
||||
if (isXhrSuccess(savingXhr)) {
|
||||
setRemoteStatus("");
|
||||
|
||||
savingFileOffset += blockSize;
|
||||
if (savingFileOffset < savingText.length) {
|
||||
var params = "action=append&filename=" + savingFilename + "&data=" + encodeURIComponent(savingText.substring(savingFileOffset, savingFileOffset + blockSize));
|
||||
savingXhr = new XMLHttpRequest();
|
||||
savingXhr.open("POST", "file-api.lc", true);
|
||||
savingXhr.onreadystatechange = handleSaveCallback;
|
||||
savingXhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
setLocalStatus("<span class=\"icon icon-loading\"></span> Saving file: " + savingFilename + " " + savingFileOffset + "/" + savingText.length + " bytes");
|
||||
savingXhr.send(params);
|
||||
} else {
|
||||
if ((savingFilename.split(".").pop() == "lua") && (savingFilename != "config.lua") && (savingFilename != "init.lua")) {
|
||||
params = "action=compile&filename=" + savingFilename;
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "file-api.lc", true);
|
||||
xhr.onreadystatechange = function() {
|
||||
if (isXhrSuccess(xhr)) {
|
||||
setLocalStatus("");
|
||||
}
|
||||
setRemoteStatus(xhr.responseText);
|
||||
};
|
||||
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
setLocalStatus("<span class=\"icon icon-loading\"></span> Compiling file: " + savingFilename);
|
||||
xhr.send(params);
|
||||
} else {
|
||||
setLocalStatus("Saved file: " + savingFilename + " " + savingText.length + " bytes");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setRemoteStatus(savingXhr.responseText);
|
||||
}
|
||||
}
|
||||
|
||||
function handleFileCallback(xhr) {
|
||||
setRemoteStatus(xhr.responseText);
|
||||
if (isXhrSuccess(xhr)) {
|
||||
loadFilelist();
|
||||
setLocalStatus("");
|
||||
}
|
||||
}
|
||||
|
||||
function loadFile() {
|
||||
var filename = curFileItem.id;
|
||||
var params = "action=load&filename=" + filename;
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "file-api.lc", true);
|
||||
xhr.onreadystatechange = function () {
|
||||
if (isXhrSuccess(xhr)) {
|
||||
setRemoteStatus("");
|
||||
editor.setValue(xhr.responseText);
|
||||
editor.markClean();
|
||||
var extension = filename.split(".").pop();
|
||||
switch (extension) {
|
||||
case "css":
|
||||
editor.setOption("mode", "css");
|
||||
break;
|
||||
case "htm":
|
||||
case "html":
|
||||
editor.setOption("mode", "htmlmixed");
|
||||
break;
|
||||
case "js":
|
||||
case "json":
|
||||
editor.setOption("mode", "javascript");
|
||||
break;
|
||||
case "lua":
|
||||
editor.setOption("mode", "lua");
|
||||
break;
|
||||
case "xml":
|
||||
editor.setOption("mode", "xml");
|
||||
break;
|
||||
}
|
||||
|
||||
setLocalStatus("");
|
||||
} else {
|
||||
//setRemoteStatus(xhr.responseText);
|
||||
}
|
||||
}
|
||||
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
setLocalStatus("<span class=\"icon icon-loading\"></span> Loading file: " + filename);
|
||||
xhr.send(params);
|
||||
}
|
||||
|
||||
function undo() {
|
||||
setLocalStatus("undo");
|
||||
editor.undo();
|
||||
}
|
||||
|
||||
function save() {
|
||||
savingText = editor.getValue();
|
||||
savingFilename = curFileItem.id;
|
||||
savingFileOffset = 0;
|
||||
var params = "action=save&filename=" + savingFilename + "&data=" + encodeURIComponent(savingText.substring(savingFileOffset, savingFileOffset + blockSize));
|
||||
savingXhr = new XMLHttpRequest();
|
||||
savingXhr.open("POST", "file-api.lc", true);
|
||||
savingXhr.onreadystatechange = handleSaveCallback;
|
||||
savingXhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
setLocalStatus("<span class=\"icon icon-loading\"></span> Saving file: " + savingFilename + " " + savingFileOffset + "/" + savingText.length + " bytes");
|
||||
savingXhr.send(params);
|
||||
}
|
||||
|
||||
function preview() {
|
||||
if (curFileItem) {
|
||||
var url = curFileItem.id;
|
||||
setLocalStatus("Preview: "+url);
|
||||
var win = window.open(url+'?', '_blank');
|
||||
win.focus();
|
||||
}
|
||||
}
|
||||
|
||||
function new_file() {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "file-api.lc", true);
|
||||
xhr.onreadystatechange = function() {
|
||||
handleFileCallback(xhr);
|
||||
};
|
||||
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
setLocalStatus("<span class=\"icon icon-loading\"></span> Creating new file");
|
||||
xhr.send("action=new");
|
||||
}
|
||||
|
||||
function rename_file() {
|
||||
if (curFileItem) {
|
||||
var filename = curFileItem.id;
|
||||
var newfilename = prompt("Rename " + filename + " to:", filename);
|
||||
if (newfilename != null) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "file-api.lc", true);
|
||||
xhr.onreadystatechange = function() {
|
||||
handleFileCallback(xhr);
|
||||
};
|
||||
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
setLocalStatus("<span class=\"icon icon-loading\"></span> Renaming file from \""+filename+"\" to \""+newfilename+"\"");
|
||||
xhr.send("action=rename&filename="+escape(filename)+"&newfilename="+escape(newfilename));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function delete_file() {
|
||||
if (curFileItem) {
|
||||
var filename = curFileItem.id;
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "file-api.lc", true);
|
||||
xhr.onreadystatechange = function() {
|
||||
handleFileCallback(xhr);
|
||||
};
|
||||
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
setLocalStatus("<span class=\"icon icon-loading\"></span> Deleting file: \""+filename+"\"");
|
||||
xhr.send("action=delete&filename="+escape(filename));
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
editor = CodeMirror(document.getElementById("editor"), {
|
||||
lineNumbers: true,
|
||||
lineWrapping: true,
|
||||
styleActiveLine: true, // activeline
|
||||
matchBrackets: true,
|
||||
matchTags: true,
|
||||
autoCloseBrackets: true,
|
||||
autoCloseTags: true,
|
||||
showTrailingSpace: true
|
||||
});
|
||||
|
||||
loadFilelist();
|
||||
|
||||
document.getElementById("undo").addEventListener("click", undo);
|
||||
document.getElementById("save").addEventListener("click", save);
|
||||
document.getElementById("preview").addEventListener("click", preview);
|
||||
document.getElementById("new").addEventListener("click", new_file);
|
||||
document.getElementById("rename").addEventListener("click", rename_file);
|
||||
document.getElementById("delete").addEventListener("click", delete_file);
|
||||
}
|
||||
|
||||
// load large size script in sequence to avoid NodeMCU overflow
|
||||
// http://codemirror.net/doc/compress.html
|
||||
loadScript("codemirror.js", function () {
|
||||
// css.js, htmlmixed.js, javascript.js, lua.js, xml.js
|
||||
loadScript("modes.js", function () {
|
||||
// active-line.js, closebrackets.js, closetag.js,
|
||||
// matchbrackets.js, matchtags.js, trailingspace.js, xml-fold.js
|
||||
loadScript("addons.js", function () {
|
||||
init();
|
||||
})
|
||||
})
|
||||
})
|
||||
14
Websocket/nodemcu-webide/src/modes.js
Executable file
14
Websocket/nodemcu-webide/src/modes.js
Executable file
File diff suppressed because one or more lines are too long
24
Websocket/test1/btn_led.lua
Normal file
24
Websocket/test1/btn_led.lua
Normal file
@@ -0,0 +1,24 @@
|
||||
-- Programme qui allume la led bleue quand on appuie le bouton flash
|
||||
-- zf181011.1749
|
||||
|
||||
print("\n btn_led.lua zf181011.2342 \n")
|
||||
|
||||
|
||||
zledbleue=0 --led bleue
|
||||
zswitch=3 --switch flash
|
||||
|
||||
gpio.mode(zswitch, gpio.INT, gpio.PULLUP)
|
||||
|
||||
function zbtn()
|
||||
if gpio.read(zswitch)==0 then
|
||||
zled_state="ON"
|
||||
gpio.write(zledbleue, gpio.LOW)
|
||||
else
|
||||
zled_state="OFF"
|
||||
gpio.write(zledbleue, gpio.HIGH)
|
||||
end
|
||||
print("btn_led: "..zled_state)
|
||||
disp_send()
|
||||
end
|
||||
|
||||
gpio.trig(zswitch, "both", zbtn)
|
||||
32
Websocket/test1/flash_led_xfois.lua
Normal file
32
Websocket/test1/flash_led_xfois.lua
Normal file
@@ -0,0 +1,32 @@
|
||||
-- programme pour faire clignoter x fois une LED avec un rapport on/off
|
||||
print("\n flash_led_xfois.lua zf181018.1428 \n")
|
||||
|
||||
zLED=0
|
||||
zTm_On_LED = 50 --> en ms
|
||||
zTm_Off_LED = 100 --> en ms
|
||||
nbfois = 0
|
||||
gpio.write(zLED, gpio.HIGH)
|
||||
gpio.mode(zLED, gpio.OUTPUT)
|
||||
ztmr_LED = tmr.create()
|
||||
|
||||
function blink_LED ()
|
||||
if nbfois >= xfois then
|
||||
print(nbfois)
|
||||
nbfois = 0
|
||||
else
|
||||
if gpio.read(zLED)==gpio.HIGH then
|
||||
gpio.write(zLED, gpio.LOW)
|
||||
tmr.alarm(ztmr_LED, zTm_Off_LED, tmr.ALARM_SINGLE, blink_LED)
|
||||
else
|
||||
gpio.write(zLED, gpio.HIGH)
|
||||
nbfois = nbfois+1
|
||||
tmr.alarm(ztmr_LED, zTm_On_LED, tmr.ALARM_SINGLE, blink_LED)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
xfois =2
|
||||
blink_LED ()
|
||||
|
||||
|
||||
|
||||
23
Websocket/test1/initz.lua
Normal file
23
Websocket/test1/initz.lua
Normal file
@@ -0,0 +1,23 @@
|
||||
--Script de bootstrap, en appuyant sur le bouton ça démarre start_boot,
|
||||
-- autrement en attendant 8 secondes cela démarre start_boot
|
||||
|
||||
print("\n init.lua zf181017.1026\n")
|
||||
|
||||
zswitch=3 --switch flash
|
||||
gpio.mode(zswitch, gpio.INT, gpio.PULLUP)
|
||||
initalarme=tmr.create()
|
||||
|
||||
function hvbouton()
|
||||
gpio.trig(zswitch, "none")
|
||||
tmr.unregister(initalarme)
|
||||
dofile("start_boot.lua")
|
||||
-- dofile("start_job.lua")
|
||||
end
|
||||
|
||||
gpio.trig(zswitch, "both", hvbouton)
|
||||
|
||||
tmr.alarm(initalarme, 8000, tmr.ALARM_SINGLE, function()
|
||||
print("\nStart\n")
|
||||
dofile("start_boot.lua")
|
||||
-- dofile("start_job.lua")
|
||||
end)
|
||||
12
Websocket/test1/rm_files.lua
Normal file
12
Websocket/test1/rm_files.lua
Normal file
@@ -0,0 +1,12 @@
|
||||
-- pour effacer TOUS les fichiers qui se trouve dans la flash du NodeMCU
|
||||
|
||||
print("\n rm_files.lua zf180907.1511 \n")
|
||||
|
||||
|
||||
l=file.list() i=0
|
||||
for k,v in pairs(l) do
|
||||
i=i+v
|
||||
file.remove(k)
|
||||
end
|
||||
print("-------------------------------")
|
||||
print("\nC'est tout effaced :-) \n")
|
||||
10
Websocket/test1/start_boot.lua
Normal file
10
Websocket/test1/start_boot.lua
Normal file
@@ -0,0 +1,10 @@
|
||||
-- Scripts à charger au moment du boot afin de pouvoir travailler avec le robot à distance
|
||||
print("\n start_boot.lua zf181102.1744 \n")
|
||||
|
||||
dofile("wifi_ap_stop.lua")
|
||||
dofile("wifi_cli_conf.lua")
|
||||
dofile("wifi_cli_start.lua")
|
||||
--dofile("web_cli.lua")
|
||||
--dofile("btn_led.lua")
|
||||
dofile("flash_led_xfois.lua")
|
||||
|
||||
14
Websocket/test1/web_cli.lua
Normal file
14
Websocket/test1/web_cli.lua
Normal file
@@ -0,0 +1,14 @@
|
||||
-- Petit script pour envoyer quelque chose sur un serveur WEB
|
||||
print("\n web_cli.lua zf181015.1625 \n")
|
||||
|
||||
function disp_send()
|
||||
-- http.get("http://192.168.4.1/?line1="..zlength.."m", nil, function(code, data)
|
||||
print("web_cli: "..zled_state)
|
||||
http.get("http://192.168.4.1/?pin="..zled_state, nil, function(code, data)
|
||||
if (code < 0) then
|
||||
print("HTTP request failed")
|
||||
else
|
||||
print(code, data)
|
||||
end
|
||||
end)
|
||||
end
|
||||
10
Websocket/test1/wifi_ap_stop.lua
Normal file
10
Websocket/test1/wifi_ap_stop.lua
Normal file
@@ -0,0 +1,10 @@
|
||||
-- Démarre le WIFI en mode AP
|
||||
print("\n wifi_ap_stop.lua zf180824.2000 \n")
|
||||
|
||||
local zmodewifi=wifi.getmode()
|
||||
if zmodewifi == wifi.SOFTAP then
|
||||
wifi.setmode(wifi.NULLMODE)
|
||||
elseif zmodewifi == wifi.STATIONAP then
|
||||
wifi.setmode(wifi.STATION)
|
||||
end
|
||||
print("WIFI AP arrêté")
|
||||
5
Websocket/test1/wifi_cli_conf.lua
Normal file
5
Websocket/test1/wifi_cli_conf.lua
Normal file
@@ -0,0 +1,5 @@
|
||||
-- Petit script pour configurer le client WIFI du NodeMCU
|
||||
print("\n wifi_cli_conf.lua zf181101.1743 \n")
|
||||
|
||||
wifi.sta.config{ssid="3g-s7", pwd="12234567", save=true}
|
||||
|
||||
14
Websocket/test1/wifi_cli_start.lua
Normal file
14
Websocket/test1/wifi_cli_start.lua
Normal file
@@ -0,0 +1,14 @@
|
||||
-- Petit script pour connecter le NodeMCU sur un AP Wifi avec l'accompte sauvé en EEPROM
|
||||
print("\n wifi_cli_start.lua zf180824.2000 \n")
|
||||
|
||||
local zmodewifi=wifi.getmode()
|
||||
if zmodewifi == wifi.NULLMODE then
|
||||
print("WIFI mode CLI only")
|
||||
wifi.setmode(wifi.STATION)
|
||||
elseif zmodewifi == wifi.SOFTAP then
|
||||
print("WIFI mode AP+CLI")
|
||||
wifi.setmode(wifi.STATIONAP)
|
||||
end
|
||||
wifi.sta.autoconnect(1)
|
||||
wifi.sta.connect()
|
||||
dofile("wifi_get_ip.lua")
|
||||
12
Websocket/test1/wifi_get_ip.lua
Normal file
12
Websocket/test1/wifi_get_ip.lua
Normal file
@@ -0,0 +1,12 @@
|
||||
-- Petit script pour obtenir l'adresse IP du NodeMCU connecté sur un AP Wifi
|
||||
print("\n wifi_get_ip.lua zf180824.2000 \n")
|
||||
|
||||
wifitimer1=tmr.create()
|
||||
tmr.alarm(wifitimer1, 1000, tmr.ALARM_AUTO , function()
|
||||
if wifi.sta.getip() == nil then
|
||||
print("Connecting to AP...")
|
||||
else
|
||||
tmr.stop(wifitimer1)
|
||||
dofile("wifi_info.lua")
|
||||
end
|
||||
end)
|
||||
28
Websocket/test1/wifi_info.lua
Normal file
28
Websocket/test1/wifi_info.lua
Normal file
@@ -0,0 +1,28 @@
|
||||
-- Petit script pour afficher les infos actuel du WIFI
|
||||
print("\n wifi_info.lua zf180824.2000 \n")
|
||||
|
||||
local zmodewifi=wifi.getmode()
|
||||
|
||||
if zmodewifi == wifi.NULLMODE then
|
||||
print("WIFI OFF")
|
||||
elseif zmodewifi == wifi.STATION then
|
||||
print("WIFI mode CLI")
|
||||
print("Connected IP:\n",wifi.sta.getip())
|
||||
do
|
||||
local sta_config=wifi.sta.getconfig(true)
|
||||
print(string.format("Current client config:\n\tssid:\"%s\"\tpassword:\"%s\"\n\tbssid:\"%s\"\tbssid_set:%s", sta_config.ssid, sta_config.pwd, sta_config.bssid, (sta_config.bssid_set and "true" or "false")))
|
||||
end
|
||||
elseif zmodewifi == wifi.SOFTAP then
|
||||
print("WIFI mode AP")
|
||||
print("AP MAC:\n\t"..wifi.ap.getmac())
|
||||
print("AP IP:\n\t"..wifi.ap.getip())
|
||||
elseif zmodewifi == wifi.STATIONAP then
|
||||
print("WIFI mode CLI+AP")
|
||||
print("Connected IP:\n",wifi.sta.getip())
|
||||
do
|
||||
local sta_config=wifi.sta.getconfig(true)
|
||||
print(string.format("Current client config:\n\tssid:\"%s\"\tpassword:\"%s\"\n\tbssid:\"%s\"\tbssid_set:%s", sta_config.ssid, sta_config.pwd, sta_config.bssid, (sta_config.bssid_set and "true" or "false")))
|
||||
end
|
||||
print("AP MAC: "..wifi.ap.getmac())
|
||||
print("AP IP: "..wifi.ap.getip())
|
||||
end
|
||||
Reference in New Issue
Block a user