63 Commits

Author SHA1 Message Date
Andreas Doebeli
ed191f28e7 got connection to mqtt broker working again 2020-09-14 03:01:16 +02:00
7fb97d164a foo 2019-08-29 10:36:20 +02:00
8573b3d5c4 some nice intro text 2019-08-29 10:36:20 +02:00
Patrick Balsiger
b04e1d83de remove redundant section 2019-08-29 10:36:19 +02:00
Patrick Balsiger
77c9c5f169 add default password to guide 2019-08-29 10:36:19 +02:00
Patrick Balsiger
0394c21459 fix typos 2019-08-29 10:36:19 +02:00
Patrick Balsiger
349b40990d simplify enduser setup 2019-08-29 10:36:19 +02:00
Patrick Balsiger
7c1db449b6 Update CI pipeline 2019-06-30 22:21:45 +02:00
Patrick Balsiger
9a75c0d0db Remove OTA, update deps 2019-06-30 22:02:56 +02:00
FrYakaTKoP
e620529157 fixed ws endpoint 2019-03-09 14:18:12 +00:00
a25f50d40c default page and config 2018-12-01 15:47:36 +01:00
ade966a77c run pattern ater startup 2018-11-29 07:05:46 +01:00
Patrick Balsiger
fb98bef55b Merge branch 'feature/4-illuchat' into 'master'
Resolve "IlluChat"

Closes #4

See merge request 0x1d/illucat!9
2018-11-24 16:37:47 +00:00
b24077de52 reenable ota 2018-11-24 17:27:21 +01:00
efa9849f1b enable ota over tcp 2018-11-24 14:15:17 +01:00
f7ba31c2d2 change chat to irc 2018-11-23 17:15:56 +01:00
62186af303 separate fw variation for chat 2018-11-23 09:46:41 +01:00
6f1afc1bc1 chat backend 2018-11-19 22:58:44 +01:00
f754e7640f update mqtt, implement basic chat fnc 2018-11-19 21:20:13 +01:00
4e69dbc471 update mqtt, implement basic chat fnc 2018-11-19 21:19:56 +01:00
4c6f1ba365 favicon 2018-11-19 13:04:19 +01:00
b05d2d4fde load config from file 2018-11-19 13:01:40 +01:00
91566eca43 update dependencies 2018-11-16 20:06:39 +01:00
Patrick Balsiger
6e63a18a53 Merge branch 'feature/8-mqcatt' into 'master'
Resolve "MQCaTT"

Closes #8

See merge request 0x1d/illucat!8
2018-11-15 23:46:42 +00:00
ae1f468969 update ui 2018-11-16 00:44:05 +01:00
abc902d5a6 stuff 2018-11-16 00:16:51 +01:00
f4e87685fb add mqtt cat 2018-11-15 23:28:32 +01:00
Patrick Balsiger
aa2713517f Merge branch 'feature/7-separation-of-concerns' into 'master'
Resolve "Separation of Concerns"

Closes #7

See merge request 0x1d/illucat!7
2018-11-15 17:55:58 +00:00
47a68e6ce4 fix deps 2018-11-15 18:15:55 +01:00
3a45f8626e move pixel plugin to separate repo 2018-11-15 18:00:07 +01:00
73495201eb ci 2018-11-15 17:29:57 +01:00
722f725bad use web plugins from plugin repo 2018-11-15 16:50:50 +01:00
11959ea30b use port property 2018-11-09 20:02:51 +01:00
8db6698690 ci 2018-11-09 19:39:49 +01:00
418d5e18fd create minimal mesh implementation 2018-11-09 19:14:03 +01:00
2c94dfe83d increase brightness 2018-11-09 19:13:03 +01:00
48ab6fca1a optimize build 2018-11-09 19:12:29 +01:00
f3df87ed96 adapt to new sprocket api 2018-11-08 18:16:21 +01:00
Patrick Balsiger
099ba3fe70 Merge branch 'feature/6-http-firmware-update' into 'master'
Resolve #6 firmware upload via http post

Closes #6

See merge request 0x1d/illucat!6
2018-11-07 14:47:24 +00:00
edfd0ebcb7 firmware upload via http post 2018-11-07 15:43:53 +01:00
Patrick Balsiger
7c2df13381 Merge branch 'cleanup' into 'master'
Cleanup

Closes #2

See merge request 0x1d/illucat!4
2018-11-05 16:15:22 +00:00
2ea9c02571 remove dispatch method as it is now supported by core 2018-11-05 16:57:43 +01:00
5a0225b040 add dispatch method again to ensure compatibility with meshcat 2018-11-05 16:25:38 +01:00
a039e591da remove unused 2018-11-05 16:19:19 +01:00
a940903bd3 reorder fnc calls 2018-11-05 15:34:14 +01:00
299f7dae65 move pixel plugin back to illucat, introduce setup method for better encapsulation of plugins in order to remove activation method 2018-11-05 15:11:45 +01:00
99dbd8379b externalize pixel stuff, add pixel instance to plugin, remove old code 2018-11-05 14:57:49 +01:00
d4d40428cc fire animation added 2018-10-29 21:00:27 +01:00
7fa3683ca6 uncouple generic web stuff into api plugin 2018-10-28 03:21:26 +01:00
a8d5cae284 separate declarations 2018-10-17 12:08:15 +02:00
a916e542fb change default animation to rainbow 2018-10-09 11:00:41 +02:00
6fc5908761 use release env in ci build 2018-10-07 13:20:24 +02:00
Patrick Balsiger
afd13ca661 Merge branch 'separation' into 'master'
Separation

See merge request 0x1d/illucat!3
2018-10-07 11:14:03 +00:00
Patrick Balsiger
09915ca94b Merge branch 'master' into 'separation'
# Conflicts:
#   data/pixelConfig.json
2018-10-07 11:13:44 +00:00
2a21775524 use illu base, reduce pixel num 2018-10-07 12:58:08 +02:00
0e13508158 set build to default env 2018-10-07 12:44:12 +02:00
75a4e3e94c minimize startup time 2018-10-07 11:47:57 +02:00
b91255fe85 run default animation earlier 2018-10-06 15:48:48 +02:00
207f90d60a separate concerns 2018-10-04 02:34:37 +02:00
0686895f33 add conn timeout to example conf 2018-10-03 22:07:20 +02:00
ffd76acb69 Merge branch 'standalone' into release/1.0.0 2018-10-03 21:59:54 +02:00
77d92155df add ap infos to example conf 2018-10-03 21:24:47 +02:00
2ba0684982 comment out all mesh stuff 2018-09-28 11:09:39 +02:00
39 changed files with 619 additions and 13364 deletions

5
.gitignore vendored
View File

@@ -1,6 +1,5 @@
.pioenvs
.piolibdeps
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.pio
.vscode
data/config.json

View File

@@ -20,7 +20,6 @@ firmware:
before_script:
- pip install -U platformio
script:
- mv data/example.config.json data/config.json
- pio run -t clean
- pio run
- pio run -t buildfs
@@ -33,8 +32,8 @@ release:
script:
- pip install awscli
- mkdir -p ${PROJECT_NAME}/${CI_COMMIT_TAG}
- mv .pioenvs/build/firmware.bin ${PROJECT_NAME}/${CI_COMMIT_TAG}
- mv .pioenvs/build/spiffs.bin ${PROJECT_NAME}/${CI_COMMIT_TAG}
- mv .pioenvs/release/firmware.bin ${PROJECT_NAME}/${CI_COMMIT_TAG}
- mv .pioenvs/release/spiffs.bin ${PROJECT_NAME}/${CI_COMMIT_TAG}
- aws s3 --endpoint-url=https://$DO_SPACE_ENDPOINT cp ./ s3://$S3_BUCKET_NAME/ --recursive --exclude "*" --include "*.bin"
artifacts:
paths:

11
.project Normal file
View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>illucat</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
</buildSpec>
<natures>
</natures>
</projectDescription>

25
.vscode/settings.json vendored
View File

@@ -1,6 +1,6 @@
{
"terminal.integrated.env.linux": {
"PATH": "/home/master/.platformio/penv/bin:/home/master/.platformio/penv:/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl",
"PATH": "/home/master/.platformio/penv/bin:/home/master/.platformio/penv:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl",
"PLATFORMIO_CALLER": "vscode"
},
"files.associations": {
@@ -15,6 +15,27 @@
"unordered_map": "cpp",
"vector": "cpp",
"tuple": "cpp",
"utility": "cpp"
"utility": "cpp",
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"cstdarg": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"exception": "cpp",
"fstream": "cpp",
"iosfwd": "cpp",
"istream": "cpp",
"limits": "cpp",
"new": "cpp",
"ostream": "cpp",
"numeric": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"cinttypes": "cpp",
"typeinfo": "cpp"
}
}

View File

@@ -1,9 +1,21 @@
# Illumination-Cat
This is the brain of the the almighty Illumination-Cat.
The Illumination-Cat (short IlluCat) is the collaborative work of several streams, ranging from 3D modeling, electronics and programming.
Originating from the Chaos-Drucker Club with the idea of having
a cool status indicator for 3D printers, the project grew beyond the original idea.
From the software point of view, the IlluCat is the exemplary model of the [Sprocket framework](https://gitlab.com/wirelos/sprocket-lib), implementing the various aspects and possibilities of the framework.
IlluCat can embed several plugins, like web interface, MQTT, IRC or even mesh networking.
As the framework supports easy integration of many available Arduino libraries, IlluCat can be easily customized to your needs. This repository contains some example implementations that you can use to build your own custom cat.
## OTA
pio run -e build && \
curl -v -F file=@.pioenvs/build/firmware.bin http://illucat.lan/update && \
curl -X POST http://illucat.lan/restart
## Resources & Documentation
[3D Model](https://www.thingiverse.com/thing:2974862)
[Installation](https://gitlab.com/0x1d/illucat/blob/master/installation.md)
[API](https://gitlab.com/0x1d/illucat/blob/master/api.md)
[OctoPrint Stuff](https://github.com/FrYakaTKoP/simple-octo-ws2812)
[Sprocket framework](https://gitlab.com/wirelos/sprocket-lib)
[Sprocket plugins](https://gitlab.com/wirelos)

2
api.md
View File

@@ -27,7 +27,7 @@ All functionality can be used by sending messages to these topics.
| pixels/brightness | Integer | Integer from 0 to 255 to set the overall brightness of the strip by bitshifting the current colors in memory. Use with caution as running the LEDs on full brightness requires a lot of power. |
## WebSocket
Endpoint: /pixel
Endpoint: /ws
Send a JSON String containing the mandatory fields.
Example:

9
data/config/mqtt.json Normal file
View File

@@ -0,0 +1,9 @@
{
"mqttClientName": "illucat1",
"mqttBrokerHost": "192.168.88.110",
"mqttBrokerPort": 1883,
"mqttRootTopic": "wirelos/illucat",
"mqttUser": "",
"mqttPass": ""
}

9
data/config/wifi.json Normal file
View File

@@ -0,0 +1,9 @@
{
"stationMode": 1,
"hostname": "illucat",
"apSSID": "illucat",
"apPassword": "illumination",
"connectTimeout": 5000,
"stationSSID": "thobens-416257",
"stationPassword": "467304645DB5"
}

View File

@@ -1,10 +0,0 @@
{
"stationMode": 0,
"hostname": "illucat",
"stationSSID": "MyWifi",
"stationPassword": "myWifiPassword",
"meshSSID": "illucat",
"meshPassword": "illumination",
"meshPort": 5555,
"channel": 5
}

6
data/ircConfig.json Normal file
View File

@@ -0,0 +1,6 @@
{
"ircServer": "chat.freenode.net",
"ircPort": 6665,
"ircNickname": "illucat",
"ircUser": "illucat"
}

9
data/mqttConfig.json Normal file
View File

@@ -0,0 +1,9 @@
{
"mqttClientName": "illucat1",
"mqttBrokerHost": "192.168.4.1",
"mqttBrokerPort": 1883,
"mqttRootTopic": "wirelos/illucat",
"mqttUser": "foo",
"mqttPass": ""
}

View File

@@ -1,7 +1,7 @@
{
"pin": 4,
"length": 32,
"brightness": 64,
"updateInterval": 50,
"length": 8,
"brightness": 127,
"updateInterval": 100,
"defaultColor": 100
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

BIN
data/www/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -2,10 +2,10 @@
<html>
<head>
<title>ESP Kit</title>
<title>IlluCat</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/png" href="/favicon-32x32.png">
<link rel="icon" type="image/png" href="/favicon.png">
<link rel="stylesheet" type="text/css" href="styles.css">
<script src="script.js"></script>
</head>
@@ -16,63 +16,57 @@
<span class="heading">Pixels</span>
<div class="content">
<ul>
<li class="form-row ParamSelect"
data-label="Hue"
data-name="hue"
data-topic="pixels/hue"
data-default="0"
data-external="/gradients.json"
></li>
<li class="form-row ParamColor"
data-name="color"
data-topic="pixels/color"
data-label="Color">
<li class="form-row ParamSelect" data-label="Hue" data-name="hue" data-topic="pixels/hue" data-default="0"
data-external="/gradients.json">
</li>
<li class="form-row ParamColor"
data-name="color"
data-topic="pixels/color2"
data-label="Color 2">
<li class="form-row ParamColor" data-name="color" data-topic="pixels/color" data-label="Color">
</li>
<li class="form-row ParamColor" data-name="color" data-topic="pixels/color2" data-label="Color 2">
</li>
<!-- data-entries='[{"text": "Color", "value": "0"}, {"text": "Rainbow", "value": "1"}, {"text": "TheaterChase", "value": "2"}, {"text": "Wipe", "value": "3"}, {"text": "Scanner", "value": "4"}, {"text": "Fade", "value": "5"}]' -->
<li class="form-row ParamSelect"
data-label="Pattern"
data-name="pattern"
data-topic="pixels/pattern"
<li class="form-row ParamSelect" data-label="Pattern" data-name="pattern" data-topic="pixels/pattern"
data-default="0"
data-entries='[{"text": "None", "value": "0"}, {"text": "Rainbow", "value": "1"}, {"text": "TheaterChase", "value": "2"}, {"text": "Color Wipe", "value": "3"}, {"text": "Scanner", "value": "4"}, {"text": "Fade", "value": "5"}]'
></li>
<li class="form-row ParamSlider"
data-name="brightness"
data-min="0"
data-max="255"
data-value="64"
data-topic="pixels/brightness"
data-label="Brightness">
data-entries='[{"text": "None", "value": "0"}, {"text": "Rainbow", "value": "1"}, {"text": "TheaterChase", "value": "2"}, {"text": "Color Wipe", "value": "3"}, {"text": "Scanner", "value": "4"}, {"text": "Fade", "value": "5"}, {"text": "Fire", "value": "6"}]'>
</li>
<li class="form-row ParamSlider"
data-name="totalSteps"
data-min="1"
data-max="255"
data-value="16"
data-topic="pixels/totalSteps"
data-label="Steps">
<li class="form-row ParamSlider" data-name="brightness" data-min="0" data-max="255" data-value="64"
data-topic="pixels/brightness" data-label="Brightness">
</li>
<li class="form-row ParamSlider" data-name="totalSteps" data-min="1" data-max="255" data-value="16"
data-topic="pixels/totalSteps" data-label="Steps">
</li>
</ul>
</div>
</form>
<!-- <div class="settings container collapsible open">
<span class="heading">IlluChat</span>
<div class="content">
<div class="Chat" data-name="Ruedi" data-label="foo" data-placeholder="msg" data-topic="out/chat/log"></div>
</div>
</div> -->
<div class="settings container collapsible">
<span class="heading">Settings</span>
<div class="content">
<h2>Network</h2>
<div class="Form" data-fileName="/config.json" data-name="configForm" data-from="/config.json" data-endpoint="/config"></div>
<div class="Form" data-fileName="/config/wifi.json" data-name="configForm" data-from="/config/wifi.json"
data-endpoint="/config"></div>
<h2>NeoPixel</h2>
<div class="Form" data-fileName="/pixelConfig.json" data-name="configForm" data-from="/pixelConfig.json" data-endpoint="/config"></div>
<div class="Form" data-fileName="/pixelConfig.json" data-name="configForm" data-from="/pixelConfig.json"
data-endpoint="/config"></div>
<h2>MQTT</h2>
<div class="Form" data-fileName="/config/mqtt.json" data-name="configForm" data-from="/config/mqtt.json"
data-endpoint="/config"></div>
<!-- <h2>IRC</h2>
<div class="Form" data-fileName="/ircConfig.json" data-name="configForm" data-from="/ircConfig.json" data-endpoint="/config"></div> -->
</div>
</div>
<div class="settings container collapsible">
<span class="heading">System</span>
<div class="content">
<div><label>Free Heap: </label><span class="js-heap"></span><span>&nbsp;bytes</span><br><br></div>
<form method='POST' action='/update' enctype='multipart/form-data'>
<input type='file' name='update'><input type='submit' value='Update'>
</form>
<br>
<button class="js-restart">Restart</button>
</div>
</div>

File diff suppressed because it is too large Load Diff

BIN
data/www/script.js.gz Normal file

Binary file not shown.

View File

@@ -306,3 +306,24 @@ form .form-row input[type="checkbox"] {
.sui select option {
background: #333333;
}
.Chat .message-container {
max-height: 200px;
overflow: auto;
}
.Chat .message-container .messages {
list-style-type: none;
}
.Chat .message-container .messages .user-label {
color: lightblue;
}
.Chat .message-container .messages .user-label:before {
color: #097479;
content: '<';
}
.Chat .message-container .messages .user-label:after {
color: #097479;
content: '>';
}
.Chat .message-container .messages .message-text {
font-weight: normal;
}

39
include/readme.txt Normal file
View File

@@ -0,0 +1,39 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

View File

@@ -4,16 +4,14 @@
- download and flash firmware and filesystem
- or: rename example.config.json to config.json, build and upload it yourself
## Enduser Setup
## Enduser Setup (Standalone)
1. Scan for access points
1. connect to illucat access point
1. open web browser and navigate to the gateway IP
1. change stationMode to 1 in the Settings section for connecting the cat to your own AP. leave it 0 to build a mesh.
1. change stationSSID and stationPassword to match your AP settings
1. change the NeoPixel settings according to your hardware. The pin needs to be specified as the pin id of your board, e.g. 4 = D2 on a Wemos D1 Mini.
1. connect to the access point "illucat" with password "illumination"
1. open a web browser and navigate to http://192.168.4.1
1. To connect the cat to your own WiFi, open the "Settings" section and change "stationMode" to 1 and set "stationSSID" and "stationPassword" according to your own access point's credentials
1. submit all changes
1. hit restart under the System section
1. illucat connects to your network and can be reached with http://illucat (or any other configured hostname)
1. open the "System" section and hit "Restart"
1. illucat connects to your network and can be reached through http://illucat (might take some time, depending on your DNS server)
## Install and setup Python
@@ -64,21 +62,6 @@ hint: you can crank the baudrate up to 921600 bps ;)
python -m esptool --port COM11 --baud 115200 write_flash 0x00000 firmware.bin 0x00300000 spiffs.bin
# Configuration after first boot
the esp will build a AP with ssid name **illu** and password **illumination**
when connected browse to **http://illucat**
now you can enter the SSID and Password of your WLAN and set StationMode to 1
then press save and reset the esp)
the Cat should now joined your network
find the ip of your cat in your DHCP table
have fun

View File

@@ -1,384 +0,0 @@
/**
* Original NeoPattern code by Bill Earl
* https://learn.adafruit.com/multi-tasking-the-arduino-part-3/overview
*
* TODO
* - cleanup the mess
* - fnc table for patterns to replace switch case
*
* Custom modifications by 0x1d:
* - default OnComplete callback that sets pattern to reverse
* - separate animation update from timer; Update now updates directly, UpdateScheduled uses timer
*/
#ifndef __NeoPattern_INCLUDED__
#define __NeoPattern_INCLUDED__
#include <Adafruit_NeoPixel.h>
using namespace std;
using namespace std::placeholders;
// Pattern types supported:
enum pattern
{
NONE = 0,
RAINBOW_CYCLE = 1,
THEATER_CHASE = 2,
COLOR_WIPE = 3,
SCANNER = 4,
FADE = 5
};
// Patern directions supported:
enum direction
{
FORWARD,
REVERSE
};
// NeoPattern Class - derived from the Adafruit_NeoPixel class
class NeoPattern : public Adafruit_NeoPixel
{
public:
// Member Variables:
pattern ActivePattern = RAINBOW_CYCLE; // which pattern is running
direction Direction = FORWARD; // direction to run the pattern
unsigned long Interval = 150; // milliseconds between updates
unsigned long lastUpdate = 0; // last update of position
uint32_t Color1 = 0;
uint32_t Color2 = 0; // What colors are in use
uint16_t TotalSteps = 32; // total number of steps in the pattern
uint16_t Index; // current step within the pattern
uint16_t completed = 0;
// FIXME return current NeoPatternState
void (*OnComplete)(int); // Callback on completion of pattern
uint8_t *frameBuffer;
int bufferSize = 0;
// Constructor - calls base-class constructor to initialize strip
NeoPattern(uint16_t pixels, uint8_t pin, uint8_t type, void (*callback)(int))
: Adafruit_NeoPixel(pixels, pin, type)
{
frameBuffer = (uint8_t*)malloc(768);
OnComplete = callback;
TotalSteps = numPixels();
}
NeoPattern(uint16_t pixels, uint8_t pin, uint8_t type)
: Adafruit_NeoPixel(pixels, pin, type)
{
frameBuffer = (uint8_t*)malloc(768);
TotalSteps = numPixels();
}
void handleStream(uint8_t *data, size_t len)
{
//const uint16_t *data16 = (uint16_t *)data;
bufferSize = len;
memcpy(frameBuffer, data, len);
}
void drawFrameBuffer(int w, uint8_t *frame, int length){
for (int i = 0; i < length; i++){
uint8_t r = frame[i];
uint8_t g = frame[++i];
uint8_t b = frame[++i];
setPixelColor(i, r ,g, b);
}
}
void onCompleteDefault(int pixels)
{
//Serial.println("onCompleteDefault");
// FIXME no specific code
if (ActivePattern == THEATER_CHASE)
{
return;
}
Reverse();
//Serial.println("pattern completed");
}
// Update the pattern
void Update()
{
switch (ActivePattern)
{
case RAINBOW_CYCLE:
RainbowCycleUpdate();
break;
case THEATER_CHASE:
TheaterChaseUpdate();
break;
case COLOR_WIPE:
ColorWipeUpdate();
break;
case SCANNER:
ScannerUpdate();
break;
case FADE:
FadeUpdate();
break;
default:
if(bufferSize > 0){
drawFrameBuffer(TotalSteps, frameBuffer, bufferSize);
}
break;
}
}
void UpdateScheduled()
{
if ((millis() - lastUpdate) > Interval) // time to update
{
lastUpdate = millis();
Update();
}
}
// Increment the Index and reset at the end
void Increment()
{
completed = 0;
if (Direction == FORWARD)
{
Index++;
if (Index >= TotalSteps)
{
Index = 0;
completed = 1;
if (OnComplete != NULL)
{
OnComplete(numPixels()); // call the comlpetion callback
}
else
{
onCompleteDefault(numPixels());
}
}
}
else // Direction == REVERSE
{
--Index;
if (Index <= 0)
{
Index = TotalSteps - 1;
completed = 1;
if (OnComplete != NULL)
{
OnComplete(numPixels()); // call the comlpetion callback
}
else
{
onCompleteDefault(numPixels());
}
}
}
}
// Reverse pattern direction
void Reverse()
{
if (Direction == FORWARD)
{
Direction = REVERSE;
Index = TotalSteps - 1;
}
else
{
Direction = FORWARD;
Index = 0;
}
}
// Initialize for a RainbowCycle
void RainbowCycle(uint8_t interval, direction dir = FORWARD)
{
ActivePattern = RAINBOW_CYCLE;
Interval = interval;
TotalSteps = 255;
Index = 0;
Direction = dir;
}
// Update the Rainbow Cycle Pattern
void RainbowCycleUpdate()
{
for (int i = 0; i < numPixels(); i++)
{
setPixelColor(i, Wheel(((i * 256 / numPixels()) + Index) & 255));
}
show();
Increment();
}
// Initialize for a Theater Chase
void TheaterChase(uint32_t color1, uint32_t color2, uint16_t interval, direction dir = FORWARD)
{
ActivePattern = THEATER_CHASE;
Interval = interval;
TotalSteps = numPixels();
Color1 = color1;
Color2 = color2;
Index = 0;
Direction = dir;
}
// Update the Theater Chase Pattern
void TheaterChaseUpdate()
{
for (int i = 0; i < numPixels(); i++)
{
if ((i + Index) % 3 == 0)
{
setPixelColor(i, Color1);
}
else
{
setPixelColor(i, Color2);
}
}
show();
Increment();
}
// Initialize for a ColorWipe
void ColorWipe(uint32_t color, uint8_t interval, direction dir = FORWARD)
{
ActivePattern = COLOR_WIPE;
Interval = interval;
TotalSteps = numPixels();
Color1 = color;
Index = 0;
Direction = dir;
}
// Update the Color Wipe Pattern
void ColorWipeUpdate()
{
setPixelColor(Index, Color1);
show();
Increment();
}
// Initialize for a SCANNNER
void Scanner(uint32_t color1, uint8_t interval)
{
ActivePattern = SCANNER;
Interval = interval;
TotalSteps = (numPixels() - 1) * 2;
Color1 = color1;
Index = 0;
}
// Update the Scanner Pattern
void ScannerUpdate()
{
for (int i = 0; i < numPixels(); i++)
{
if (i == Index) // Scan Pixel to the right
{
setPixelColor(i, Color1);
}
else if (i == TotalSteps - Index) // Scan Pixel to the left
{
setPixelColor(i, Color1);
}
else // Fading tail
{
setPixelColor(i, DimColor(getPixelColor(i)));
}
}
show();
Increment();
}
// Initialize for a Fade
void Fade(uint32_t color1, uint32_t color2, uint16_t steps, uint8_t interval, direction dir = FORWARD)
{
ActivePattern = FADE;
Interval = interval;
TotalSteps = steps;
Color1 = color1;
Color2 = color2;
Index = 0;
Direction = dir;
}
// Update the Fade Pattern
void FadeUpdate()
{
// Calculate linear interpolation between Color1 and Color2
// Optimise order of operations to minimize truncation error
uint8_t red = ((Red(Color1) * (TotalSteps - Index)) + (Red(Color2) * Index)) / TotalSteps;
uint8_t green = ((Green(Color1) * (TotalSteps - Index)) + (Green(Color2) * Index)) / TotalSteps;
uint8_t blue = ((Blue(Color1) * (TotalSteps - Index)) + (Blue(Color2) * Index)) / TotalSteps;
ColorSet(Color(red, green, blue));
show();
Increment();
}
// Calculate 50% dimmed version of a color (used by ScannerUpdate)
uint32_t DimColor(uint32_t color)
{
// Shift R, G and B components one bit to the right
uint32_t dimColor = Color(Red(color) >> 1, Green(color) >> 1, Blue(color) >> 1);
return dimColor;
}
// Set all pixels to a color (synchronously)
void ColorSet(uint32_t color)
{
for (int i = 0; i < numPixels(); i++)
{
setPixelColor(i, color);
}
show();
}
// Returns the Red component of a 32-bit color
uint8_t Red(uint32_t color)
{
return (color >> 16) & 0xFF;
}
// Returns the Green component of a 32-bit color
uint8_t Green(uint32_t color)
{
return (color >> 8) & 0xFF;
}
// Returns the Blue component of a 32-bit color
uint8_t Blue(uint32_t color)
{
return color & 0xFF;
}
// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos)
{
//if(WheelPos == 0) return Color(0,0,0);
WheelPos = 255 - WheelPos;
if (WheelPos < 85)
{
return Color(255 - WheelPos * 3, 0, WheelPos * 3);
}
else if (WheelPos < 170)
{
WheelPos -= 85;
return Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
else
{
WheelPos -= 170;
return Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
}
};
#endif

View File

@@ -1,96 +0,0 @@
#ifndef __NEOPATTERN_STATE__
#define __NEOPATTERN_STATE__
#include <ArduinoJson.h>
#include "NeoPattern_api_json.h"
#include "NeoPattern_api_modes.cpp"
#include "utils_print.h"
#include "JsonStruct.h"
// TODO move ARRAY_LENGTH to core lib
#define ARRAY_LENGTH(array) sizeof(array)/sizeof(array[0])
struct NeoPixelConfig : public JsonStruct {
int pin;
int length;
int brightness;
int updateInterval;
int defaultColor;
void mapJsonObject(JsonObject& root) {
root["pin"] = pin;
root["length"] = length;
root["brightness"] = brightness;
root["updateInterval"] = updateInterval;
root["defaultColor"] = defaultColor;
}
void fromJsonObject(JsonObject& json) {
pin = getIntAttrFromJson(json, "pin");
length = getIntAttrFromJson(json, "length");
brightness = getIntAttrFromJson(json, "brightness");
updateInterval = getIntAttrFromJson(json, "updateInterval");
defaultColor = getIntAttrFromJson(json, "defaultColor");
}
};
struct NeoPatternState : public JsonStruct {
uint pattern = 0;
uint color= 0;
uint color2= 0;
uint totalSteps = 16;
uint brightness = 64;
void mapJsonObject(JsonObject& root) {
root["pattern"] = pattern;
root["color"] = color;
root["color2"] = color2;
root["totalSteps"] = totalSteps;
root["brightness"] = brightness;
}
// Map a json object to this struct.
void fromJsonObject(JsonObject& json){
if(!verifyJsonObject(json)){
PRINT_MSG(Serial, "fromJsonObject", "cannot parse JSON");
valid = 0;
return;
}
color = getIntAttrFromJson(json, "color", color);
color2 = getIntAttrFromJson(json, "color2", color2);
pattern = getIntAttrFromJson(json, "pattern", pattern);
brightness = getIntAttrFromJson(json, "brightness", brightness);
totalSteps = getIntAttrFromJson(json, "totalSteps", totalSteps);
valid = 1;
};
};
struct NeoPatternDto : public JsonStruct {
uint mode;
uint value;
const char* valueStr;
// ------------------------------------------------------------------------------------------
//Check if given object is valid and contains fields: JSON_MODE_NODE, JSON_VALUE
int verifyJsonObject(JsonObject& json){
return json.success()
&& json.containsKey(JSON_MODE_NODE)
&& json.containsKey(JSON_VALUE);
};
void mapJsonObject(JsonObject& root) {
root[JSON_MODE_NODE] = mode;
root[JSON_VALUE] = value;
}
// Map a json object to this struct.
void fromJsonObject(JsonObject& json){
if(!verifyJsonObject(json)){
PRINT_MSG(Serial, "fromJsonObject", "cannot parse JSON");
valid = 0;
return;
}
mode = atoi(json[JSON_MODE_NODE]);
mode = mode < ARRAY_LENGTH(PIXEL_FNCS) ? mode : 0;
value = json[JSON_VALUE];
valueStr = json[JSON_VALUE];
valid = 1;
};
};
#endif

View File

@@ -1,16 +0,0 @@
#ifndef __PIXEL_JSON_API__
#define __PIXEL_JSON_API__
/*
modes: PIXELS_OFF = 0, COLOR_WHEEL_MODE = 1, COLOR_MODE = 2, PATTERN_MODE = 3
patterns: NONE = 0, RAINBOW_CYCLE = 1, THEATER_CHASE = 2, COLOR_WIPE = 3, SCANNER = 4, FADE = 5
{
"mode": int,
"value": int || String
}
*/
#define JSON_MODE_NODE "mode"
#define JSON_VALUE "value"
#define JSON_ACTION_NODE "action"
#endif

View File

@@ -1,64 +0,0 @@
#ifndef __NEOPATTERN_API_MODES__
#define __NEOPATTERN_API_MODES__
#include "NeoPattern.cpp"
enum PIXEL_MODE { PIXELS_OFF = 0, COLOR_WHEEL_MODE = 1, COLOR_MODE = 2, PATTERN_MODE = 3};
typedef void (*PIXEL_FP)(NeoPattern*, const char *);
/*
Array of function pointers to be used as lookup table using the int values of PIXEL_MODE.
TODO header file + separate functions instead of lambdas
*/
const PIXEL_FP PIXEL_FNCS[] = {
/*
PIXESL_OFF
Sets all pixels to black.
*/
[](NeoPattern* pixels, const char *color){
pixels->clear();
pixels->ColorSet(0);
},
/*
COLOR_WHEEL_MODE
Input: integer color from 0 to 155
Uses the color wheel to set a color.
If given integer is <= 1, set the color to black.
By using this function, Color1 and Color2 is set on the pixels;
Color1 = new color, Color2 = last color.
*/
[](NeoPattern* pixels, const char *color){
int c1 = atoi(color);
int c2 = pixels->Color1;
pixels->Color1 = c1;
pixels->Color2 = c2;
pixels->ActivePattern = NONE;
if(c1 <= 1) {
pixels->ColorSet(0);
return;
}
pixels->ColorSet(pixels->Wheel(c1));
},
/*
COLOR_MODE
sets the color from an rgb int
*/
[](NeoPattern* pixels, const char *color){
pixels->ActivePattern = NONE;
pixels->ColorSet(atoi(color));
},
/*
PATTERN_MODE
Input: id of the pattern
Sets the active pattern on the strip.
As every pattern has another API, all fields need to be set before, for example by using COLOR_WHEEL_MODE.
*/
[](NeoPattern* pixels, const char *id){
pattern p = (pattern)atoi(id);
//pixels->Interval = 50;
//pixels->TotalSteps = pixels->numPixels();
pixels->ActivePattern = p;
}
};
#endif

View File

@@ -1,25 +0,0 @@
#include "utils_print.h"
int FORMAT_BUFFER_SIZE(const char* format, ...) {
va_list args;
va_start(args, format);
int result = vsnprintf(NULL, 0, format, args);
va_end(args);
return result + 1; // safe byte for \0
}
void PRINT_MSG(Print &out, const char* prefix, const char* format, ...) {
if(SPROCKET_PRINT){
out.print(String(prefix) + String(": "));
char formatString[128], *ptr;
strncpy_P( formatString, format, sizeof(formatString) ); // copy in from program mem
// null terminate - leave last char since we might need it in worst case for result's \0
formatString[ sizeof(formatString)-2 ]='\0';
ptr=&formatString[ strlen(formatString)+1 ]; // our result buffer...
va_list args;
va_start (args,format);
vsnprintf(ptr, sizeof(formatString)-1-strlen(formatString), formatString, args );
va_end (args);
formatString[ sizeof(formatString)-1 ]='\0';
out.println(ptr);
}
}

View File

@@ -1,15 +0,0 @@
#ifndef __SPROCKET_UTILS__
#define __SPROCKET_UTILS__
#include <Arduino.h>
#ifndef SPROCKET_PRINT
#define SPROCKET_PRINT 1
#endif
// TODO move to sprocket
int FORMAT_BUFFER_SIZE(const char* format, ...);
void PRINT_MSG(Print &out, const char* prefix, const char* format, ...);
#endif

View File

@@ -1,126 +0,0 @@
#ifndef __WSUTILS_H___
#define __WSUTILS_H___
#include <Arduino.h>
#include <ESPAsyncWebServer.h>
#include <AsyncWebSocket.h>
#include <ESPAsyncTCP.h>
class WsUtils {
public:
static String parseFrame(AwsEventType type, void * arg, uint8_t *data, size_t len) {
String msg = "";
if(type == WS_EVT_DATA){
AwsFrameInfo * info = (AwsFrameInfo*)arg;
if(info->opcode == WS_TEXT){
for(size_t i=0; i < info->len; i++) {
msg += (char) data[i];
}
} else {
char buff[3];
for(size_t i=0; i < info->len; i++) {
sprintf(buff, "%02x ", (uint8_t) data[i]);
msg += buff ;
}
}
}
return msg;
}
static String parseFrameAsString(AwsEventType type, void * arg, uint8_t *data, size_t len, int start = 0) {
String msg = "";
if(type == WS_EVT_DATA){
AwsFrameInfo * info = (AwsFrameInfo*)arg;
//if(info->final && info->index == 0 && info->len == len){
if(info->opcode == WS_TEXT){
for(size_t i=start; i < info->len; i++) {
msg += (char) data[i];
}
} else {
char buff[3];
for(size_t i=start; i < info->len; i++) {
sprintf(buff, "%02x ", (uint8_t) data[i]);
msg += buff ;
}
}
//}
}
return msg;
}
/* static void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len) {
if(type == WS_EVT_CONNECT){
Serial.printf("ws[%s][%u] connect\n", server->url(), client->id());
client->printf("Hello Client %u :)", client->id());
client->ping();
} else if(type == WS_EVT_DISCONNECT){
Serial.printf("ws[%s][%u] disconnect: %u\n", server->url(), client->id());
} else if(type == WS_EVT_ERROR){
Serial.printf("ws[%s][%u] error(%u): %s\n", server->url(), client->id(), *((uint16_t*)arg), (char*)data);
} else if(type == WS_EVT_PONG){
Serial.printf("ws[%s][%u] pong[%u]: %s\n", server->url(), client->id(), len, (len)?(char*)data:"");
} else if(type == WS_EVT_DATA){
AwsFrameInfo * info = (AwsFrameInfo*)arg;
String msg = "";
//the whole message is in a single frame and we got all of it's data
if(info->final && info->index == 0 && info->len == len){
Serial.printf("ws[%s][%u] %s-message[%llu]: ", server->url(), client->id(), (info->opcode == WS_TEXT)?"text":"binary", info->len);
if(info->opcode == WS_TEXT){
for(size_t i=0; i < info->len; i++) {
msg += (char) data[i];
}
} else {
char buff[3];
for(size_t i=0; i < info->len; i++) {
sprintf(buff, "%02x ", (uint8_t) data[i]);
msg += buff ;
}
}
Serial.printf("%s\n",msg.c_str());
if(info->opcode == WS_TEXT)
client->text("I got your text message");
else
client->binary("I got your binary message");
}
//message is comprised of multiple frames or the frame is split into multiple packets
else {
if(info->index == 0){
if(info->num == 0)
Serial.printf("ws[%s][%u] %s-message start\n", server->url(), client->id(), (info->message_opcode == WS_TEXT)?"text":"binary");
Serial.printf("ws[%s][%u] frame[%u] start[%llu]\n", server->url(), client->id(), info->num, info->len);
}
Serial.printf("ws[%s][%u] frame[%u] %s[%llu - %llu]: ", server->url(), client->id(), info->num, (info->message_opcode == WS_TEXT)?"text":"binary", info->index, info->index + len);
if(info->opcode == WS_TEXT){
for(size_t i=0; i < info->len; i++) {
msg += (char) data[i];
}
} else {
char buff[3];
for(size_t i=0; i < info->len; i++) {
sprintf(buff, "%02x ", (uint8_t) data[i]);
msg += buff ;
}
}
Serial.printf("%s\n",msg.c_str());
if((info->index + len) == info->len){
Serial.printf("ws[%s][%u] frame[%u] end[%llu]\n", server->url(), client->id(), info->num, info->len);
if(info->final){
Serial.printf("ws[%s][%u] %s-message end\n", server->url(), client->id(), (info->message_opcode == WS_TEXT)?"text":"binary");
if(info->message_opcode == WS_TEXT)
client->text("I got your text message");
else
client->binary("I got your binary message");
}
}
}
}
} */
};
#endif

View File

@@ -8,29 +8,30 @@
; Please visit documentation for the other options and examples
; http://docs.platformio.org/page/projectconf.html
[platformio]
env_default = build
;[platformio]
;env_default = build
[common]
framework = arduino
platform = espressif8266
platform = espressif8266@2.0.4
board = esp12e
upload_speed = 921600
monitor_baud = 115200
upload_speed = 115200
monitor_baud = 74880
lib_deps =
Hash
ESPAsyncTCP
TaskScheduler
SPIFFS
painlessMesh
ESP8266mDNS
ArduinoOTA
ArduinoJson
ESP Async WebServer
ESPAsyncTCP
ArduinoJson@5.13.4
Adafruit NeoPixel
ESPAsyncTCP
ESP8266mDNS
ESP Async WebServer
https://gitlab.com/wirelos/sprocket-lib.git#develop
https://gitlab.com/wirelos/sprocket-plugin-neopixel.git
[env:build]
src_filter = +<*> -<var/> +<var/wifi/>
platform = ${common.platform}
board = ${common.board}
upload_speed = ${common.upload_speed}
@@ -39,9 +40,25 @@ framework = ${common.framework}
build_flags = -Wl,-Teagle.flash.4m1m.ld
-DSPROCKET_PRINT=1
lib_deps = ${common.lib_deps}
https://gitlab.com/wirelos/sprocket-core.git#develop
https://gitlab.com/wirelos/sprocket-network-wifi.git#next
https://gitlab.com/wirelos/sprocket-plugin-web.git#next
[env:build-mesh]
src_filter = +<*> -<var/> +<var/wifiMesh/>
platform = ${common.platform}
board = ${common.board}
upload_speed = ${common.upload_speed}
monitor_baud = ${common.monitor_baud}
framework = ${common.framework}
build_flags = -Wl,-Teagle.flash.4m1m.ld
-DSPROCKET_PRINT=1
lib_deps = ${common.lib_deps}
https://gitlab.com/wirelos/painlessMesh.git
https://gitlab.com/wirelos/sprocket-network-mesh.git#forked-mesh
[env:release]
src_filter = +<*> -<var/> +<var/wifi/>
platform = ${common.platform}
board = ${common.board}
upload_speed = ${common.upload_speed}
@@ -50,16 +67,38 @@ framework = ${common.framework}
build_flags = -Wl,-Teagle.flash.4m1m.ld
-DSPROCKET_PRINT=0
lib_deps = ${common.lib_deps}
https://gitlab.com/wirelos/sprocket-core.git#master
https://gitlab.com/wirelos/sprocket-network-wifi.git#next
https://gitlab.com/wirelos/sprocket-plugin-web.git#next
[env:nodemcu]
[env:mqcatt]
src_filter = +<*> -<var/> +<var/mqcatt/>
platform = ${common.platform}
board = nodemcu
board = ${common.board}
upload_speed = ${common.upload_speed}
monitor_baud = ${common.monitor_baud}
framework = ${common.framework}
build_flags = -Wl,-Teagle.flash.4m1m.ld
-DSPROCKET_PRINT=1
lib_deps = ${common.lib_deps}
https://gitlab.com/wirelos/sprocket-core.git#develop
https://gitlab.com/wirelos/sprocket-network-wifi.git#next
https://gitlab.com/wirelos/sprocket-plugin-web.git#next
https://gitlab.com/wirelos/sprocket-plugin-mqtt.git#next
PubSubClient
[env:illuchat]
src_filter = +<*> -<var/> +<var/illuchat/>
platform = ${common.platform}
board = ${common.board}
upload_speed = ${common.upload_speed}
monitor_baud = ${common.monitor_baud}
framework = ${common.framework}
build_flags = -Wl,-Teagle.flash.4m1m.ld
-DSPROCKET_PRINT=1
lib_deps = ${common.lib_deps}
https://gitlab.com/wirelos/sprocket-network-wifi.git#next
https://gitlab.com/wirelos/sprocket-plugin-web.git#next
https://gitlab.com/wirelos/sprocket-plugin-irc.git
https://gitlab.com/wirelos/sprocket-plugin-mqtt.git#next
PubSubClient
ArduinoIRC

View File

@@ -1,151 +1,38 @@
#ifndef __MESH_APP__
#define __MESH_APP__
#include <painlessMesh.h>
#include <base/MeshSprocket.h>
#include <MeshNet.h>
#ifndef __ILLUCAT__
#define __ILLUCAT__
#include "config.h"
#include "NeoPattern.cpp"
#include "NeoPatternDto.h"
#include "NeoPattern_api_json.h"
#include "NeoPattern_api_modes.cpp"
#include "utils_print.h"
#include "utils_ws.h"
#include <plugins/WebSO.h>
#include <plugins/OtaTcpPlugin.cpp>
#include <plugins/WebServerPlugin.cpp>
#include <plugins/WebConfigPlugin.cpp>
#include <TaskScheduler.h>
#include <Sprocket.h>
#include "WebServerConfig.h"
#include "WebServerPlugin.h"
#include "WebConfigPlugin.h"
#include "WebApiPlugin.h"
#include "PixelPlugin.h"
using namespace std;
using namespace std::placeholders;
class IlluCat : public MeshSprocket {
class IlluCat : public Sprocket
{
public:
NeoPattern* pixels;
NeoPatternDto defaultState;
NeoPatternDto state;
AsyncWebServer *server;
AsyncWebSocket* ws;
AsyncWebSocket* wsStream;
NeoPixelConfig pixelConfig;
SprocketConfig sprocketConfig;
OtaConfig otaConfig;
WebServerConfig webConfig;
SprocketMessage currentMessage;
IlluCat(SprocketConfig cfg, OtaConfig otaCfg, WebServerConfig webCfg/* , NeoPixelConfig pixelCfg */) : MeshSprocket(cfg) {
//pixelConfig = pixelCfg;
IlluCat(SprocketConfig cfg, WebServerConfig webCfg) : Sprocket(cfg)
{
sprocketConfig = cfg;
otaConfig = otaCfg;
webConfig = webCfg;
pixelConfig.pin = 4;
pixelConfig.length = 8;
pixelConfig.brightness = 32;
pixelConfig.updateInterval = 100;
pixelConfig.defaultColor = 100;
}
virtual void scanningAnimation() {
pixels->Scanner(pixels->Wheel(COLOR_NOT_CONNECTED), pixelConfig.updateInterval);
}
virtual void defaultAnimation() {
String defaultStr = String(defaultState.value);
PIXEL_FNCS[defaultState.mode](pixels, defaultStr.c_str());
}
Sprocket* activate(Scheduler* scheduler, Network* network) {
net = static_cast<MeshNet*>(network);
// load config files from SPIFFS
if(SPIFFS.begin()){
pixelConfig.fromFile("/pixelConfig.json");
defaultState.fromFile("/pixelState.json");
state = defaultState;
}
// initialize services
pixels = new NeoPattern(pixelConfig.length, pixelConfig.pin, NEO_GRB + NEO_KHZ800);
server = new AsyncWebServer(80);
ws = new AsyncWebSocket("/pixel");
wsStream = new AsyncWebSocket("/stream");
// add plugins
addPlugin(new OtaTcpPlugin(otaConfig));
server = new AsyncWebServer(webConfig.port);
server->serveStatic(PIXEL_CONFIG_FILE, SPIFFS, "pixelConfig.json");
addPlugin(new PixelPlugin());
addPlugin(new WebServerPlugin(webConfig, server));
addPlugin(new WebConfigPlugin(server));
addPlugin(new PixelPlugin(pixelConfig, pixels));
defaultAnimation();
String softApPrt = "SoftAP IP: " + WiFi.softAPIP().toString();
PRINT_MSG(Serial, SPROCKET_TYPE, softApPrt.c_str());
// TODO move to plugin
// setup web stuff
server->serveStatic("/pixelConfig.json", SPIFFS, "pixelConfig.json");
server->on("/pixel/api", HTTP_POST, bind(&IlluCat::patternWebRequestHandler, this, _1));
ws->onEvent(bind(&IlluCat::onWsEvent, this, _1, _2, _3, _4, _5, _6));
server->addHandler(ws);
wsStream->onEvent(bind(&IlluCat::onStream, this, _1, _2, _3, _4, _5, _6));
server->addHandler(wsStream);
return MeshSprocket::activate(scheduler, network);
} using MeshSprocket::activate;
// TODO move to utils
String getRequestParameterOrDefault(AsyncWebServerRequest *request, String param, String defaultValue, bool isPost = true){
if(request->hasParam(param, isPost)) {
return request->getParam(param, isPost)->value();
}
return defaultValue;
addPlugin(new WebApiPlugin(server));
}
void onStream(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len) {
if(type == WS_EVT_DATA){
PRINT_MSG(Serial, SPROCKET_TYPE, WsUtils::parseFrameAsString(type, arg, data, len, 0).c_str());
pixels->ActivePattern = NONE;
pixels->handleStream(data, len);
}
}
void patternWebRequestHandler(AsyncWebServerRequest *request) {
PRINT_MSG(Serial, SPROCKET_TYPE, "POST /pixel/api");
currentMessage.topic = getRequestParameterOrDefault(request, "topic", "");
currentMessage.payload = getRequestParameterOrDefault(request, "payload", "");
currentMessage.broadcast = atoi(getRequestParameterOrDefault(request, "broadcast", "0").c_str());
String msg = currentMessage.toJsonString();
publish(currentMessage.topic, currentMessage.payload);
if(currentMessage.broadcast){
net->mesh.sendBroadcast(msg);
}
request->send(200, "text/plain", msg);
}
virtual void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len) {
if(type == WS_EVT_DATA){
String frame = WsUtils::parseFrameAsString(type, arg, data, len, 0);
dispatch(0, frame);
net->mesh.sendBroadcast(frame);
}
}
virtual void dispatch( uint32_t from, String &msg ) {
currentMessage.fromJsonString(msg);
if(currentMessage.valid){
currentMessage.from = from;
publish(currentMessage.topic, currentMessage.payload);
}
}
void loop(){
MeshSprocket::loop();
}
};
#endif

View File

@@ -1,96 +0,0 @@
#ifndef __PIXEL_PLUGIN__
#define __PIXEL_PLUGIN__
#define _TASK_SLEEP_ON_IDLE_RUN
#define _TASK_STD_FUNCTION
#include "TaskSchedulerDeclarations.h"
#include "MeshNet.h"
#include "Plugin.h"
#include "NeoPatternDto.h"
#include "NeoPattern.cpp"
using namespace std;
using namespace std::placeholders;
class PixelPlugin : public Plugin {
private:
NeoPixelConfig pixelConfig;
NeoPattern* pixels;
NeoPatternState state;
public:
Task animation;
PixelPlugin(NeoPixelConfig cfg, NeoPattern* neoPattern){
pixelConfig = cfg;
pixels = neoPattern;
pixels->begin();
pixels->setBrightness(pixelConfig.brightness);
}
void activate(Scheduler* userScheduler, Network* network){
subscribe("pixels/colorWheel", bind(&PixelPlugin::colorWheel, this, _1));
subscribe("pixels/color", bind(&PixelPlugin::setColor, this, _1));
subscribe("pixels/color2", bind(&PixelPlugin::setColor2, this, _1));
subscribe("pixels/pattern", bind(&PixelPlugin::setPattern, this, _1));
subscribe("pixels/totalSteps", bind(&PixelPlugin::setTotalSteps, this, _1));
subscribe("pixels/brightness", bind(&PixelPlugin::setBrightness, this, _1));
subscribe("pixels/state", bind(&PixelPlugin::setState, this, _1));
animation.set(TASK_MILLISECOND * pixelConfig.updateInterval, TASK_FOREVER, bind(&PixelPlugin::animate, this));
userScheduler->addTask(animation);
animation.enable();
PRINT_MSG(Serial, SPROCKET_TYPE, "NeoPixels activated");
}
void setState(String msg) {
PRINT_MSG(Serial, SPROCKET_TYPE, msg.c_str());
state.fromJsonString(msg);
//pixels->setBrightness(state.brightness);
//pixels->ColorSet(state.color);
pixels->Index = 0;
pixels->Color1 = state.color;
pixels->Color2 = state.color2;
pixels->TotalSteps = state.totalSteps;
pixels->ActivePattern = (pattern) state.pattern;
pixels->Direction = FORWARD;
}
void colorWheel(String msg){
int color = atoi(msg.c_str());
pixels->ActivePattern = NONE;
pixels->ColorSet(pixels->Wheel(color));
}
void setTotalSteps(String msg){
pixels->TotalSteps = atoi(msg.c_str());
}
void setBrightness(String msg){
int inVal = atoi(msg.c_str());
pixels->setBrightness(inVal);
pixels->show();
}
void setColor(String msg){
pixels->ActivePattern = NONE;
pixels->Color1 = atoi(msg.c_str());
//if(pixels->ActivePattern == NONE){
pixels->ColorSet(pixels->Color1);
//}
}
void setColor2(String msg){
pixels->Color2 = atoi(msg.c_str());
}
void setPattern(String msg){
pixels->Index = 0;
pixels->Direction = FORWARD;
pixels->ActivePattern = (pattern)atoi(msg.c_str());
}
void animate(){
pixels->Update();
}
void enable(){
animation.enable();
}
void disable(){
animation.disable();
}
};
#endif

View File

@@ -1,26 +1,32 @@
#ifndef __MESH_CONFIG__
#define __MESH_CONFIG__
#ifndef __ILLUCAT_CONFIG__
#define __ILLUCAT_CONFIG__
// Scheduler config
#define _TASK_SLEEP_ON_IDLE_RUN
#define _TASK_STD_FUNCTION
#define _TASK_PRIORITY
// Chip config
#define SPROCKET_TYPE "ILLUCAT"
#define SERIAL_BAUD_RATE 115200
#define STARTUP_DELAY 3000
#define SERIAL_BAUD_RATE 74880
#define STARTUP_DELAY 5000
// Mesh config
#define SPROCKET_MODE 0
#define WIFI_CHANNEL 11
#define MESH_PORT 5555
#define AP_SSID "illucat"
#define AP_PASSWORD "illumination"
#define MESH_PREFIX "illucat-mesh"
#define MESH_PASSWORD "th3r31sn0sp00n"
#define STATION_SSID "MyAP"
#define STATION_PASSWORD "th3r31sn0sp00n"
#define STATION_SSID "thobens-416257"
#define STATION_PASSWORD "467304645DB5"
#define HOSTNAME "illucat"
#define CONNECT_TIMEOUT 10000
#define MESH_DEBUG_TYPES ERROR | STARTUP | CONNECTION
//ERROR | MESH_STATUS | CONNECTION | SYNC | COMMUNICATION | GENERAL | MSG_TYPES | REMOTE
//#define MESH_DEBUG_TYPES ERROR | MESH_STATUS | CONNECTION | SYNC | COMMUNICATION | GENERAL | MSG_TYPES | REMOTE
#define PIXEL_CONFIG_FILE "/pixelConfig.json"
// OTA config
#define OTA_PORT 8266
@@ -30,6 +36,7 @@
#define WEB_CONTEXT_PATH "/"
#define WEB_DOC_ROOT "/www"
#define WEB_DEFAULT_FILE "index.html"
#define WEB_PORT 80
// NeoPixel
#define LED_STRIP_PIN D2
@@ -39,5 +46,6 @@
#define LED_STRIP_DEFAULT_COLOR 100
#define COLOR_CONNECTED LED_STRIP_DEFAULT_COLOR
#define COLOR_NOT_CONNECTED 255
#define LED_STRIP_DEFAULT_PATTERN 1
#endif

View File

@@ -1,25 +0,0 @@
#include "config.h"
#include "MeshNet.h"
#include "IlluCat.h"
MeshNet net({
SPROCKET_MODE, WIFI_CHANNEL,
MESH_PORT, MESH_PREFIX, MESH_PASSWORD,
STATION_SSID, STATION_PASSWORD, HOSTNAME,
MESH_DEBUG_TYPES
});
IlluCat sprocket(
{ STARTUP_DELAY, SERIAL_BAUD_RATE },
{ OTA_PORT, OTA_PASSWORD },
{ WEB_CONTEXT_PATH, WEB_DOC_ROOT, WEB_DEFAULT_FILE }/* ,
{ LED_STRIP_PIN, LED_STRIP_LENGTH, LED_STRIP_BRIGHTNESS, LED_STRIP_UPDATE_INTERVAL, LED_STRIP_DEFAULT_COLOR } */
);
void setup() {
sprocket.join(net);
}
void loop() {
sprocket.loop();
yield();
}

View File

@@ -0,0 +1,62 @@
#ifndef __ILLUCHAT_CONFIG__
#define __ILLUCHAT_CONFIG__
// Scheduler config
#define _TASK_SLEEP_ON_IDLE_RUN
#define _TASK_STD_FUNCTION
#define _TASK_PRIORITY
// Chip config
#define SPROCKET_TYPE "ILLUCAT"
#define SERIAL_BAUD_RATE 115200
#define STARTUP_DELAY 1000
// Network config
#define WIFI_MODE 0
#define WIFI_CHANNEL 11
#define AP_SSID "illucat"
#define AP_PASSWORD "illumination"
#define MESH_PREFIX "illucat-mesh"
#define MESH_PASSWORD "th3r31sn0sp00n"
#define STATION_SSID "MyAP"
#define STATION_PASSWORD "th3r31sn0sp00n"
#define HOSTNAME "illucat"
#define CONNECT_TIMEOUT 10000
// config files
#define PIXEL_CONFIG_FILE "/pixelConfig.json"
#define MQTT_CONFIG_FILE "/mqttConfig.json"
#define IRC_CONFIG_FILE "/ircConfig.json"
// NeoPixel
#define LED_STRIP_PIN D2
#define LED_STRIP_LENGTH 8
#define LED_STRIP_BRIGHTNESS 48
#define LED_STRIP_UPDATE_INTERVAL 200
#define LED_STRIP_DEFAULT_COLOR 100
#define COLOR_CONNECTED LED_STRIP_DEFAULT_COLOR
#define COLOR_NOT_CONNECTED 255
#define IRC_SERVER "chat.freenode.net"
#define IRC_PORT 6665
#define IRC_NICKNAME ""
#define IRC_USER ""
// OTA config
#define OTA_PORT 8266
#define OTA_PASSWORD ""
// WebServer
#define WEB_CONTEXT_PATH "/"
#define WEB_DOC_ROOT "/www"
#define WEB_DEFAULT_FILE "index.html"
#define WEB_PORT 80
// mqtt config
#define MQTT_CLIENT_NAME "illucat"
#define MQTT_HOST "192.168.1.2"
#define MQTT_PORT 1883
#define MQTT_ROOT_TOPIC "wirelos/led/illucat"
#endif

78
src/var/illuchat/main.cpp Normal file
View File

@@ -0,0 +1,78 @@
#include "illuchat_config.h"
#include <WiFiNet.h>
#include <Sprocket.h>
#include <ESPAsyncWebServer.h>
#include <WebServerConfig.h>
#include <WebServerPlugin.h>
#include <WebConfigPlugin.h>
#include <WebApiPlugin.h>
#include <PixelPlugin.h>
#include <IrcPlugin.h>
#include <MqttPlugin.h>
WiFiNet *network;
Sprocket *sprocket;
WebServerPlugin *webServerPlugin;
WebConfigPlugin *webConfigPlugin;
WebApiPlugin *webApiPlugin;
PixelPlugin *pixelPlugin;
IrcPlugin *ircPlugin;
MqttPlugin *mqttPlugin;
void setup()
{
const char *chipName = String("Sprocket" + String(ESP.getChipId())).c_str();
sprocket = new Sprocket({STARTUP_DELAY, SERIAL_BAUD_RATE});
pixelPlugin = new PixelPlugin({LED_STRIP_PIN, LED_STRIP_LENGTH, LED_STRIP_BRIGHTNESS, LED_STRIP_UPDATE_INTERVAL});
ircPlugin = new IrcPlugin({IRC_SERVER, IRC_PORT, chipName, chipName});
mqttPlugin = new MqttPlugin({MQTT_CLIENT_NAME, MQTT_HOST, MQTT_PORT, MQTT_ROOT_TOPIC});
webServerPlugin = new WebServerPlugin({WEB_CONTEXT_PATH, WEB_DOC_ROOT, WEB_DEFAULT_FILE, WEB_PORT});
webConfigPlugin = new WebConfigPlugin(webServerPlugin->server);
webApiPlugin = new WebApiPlugin(webServerPlugin->server);
sprocket->addPlugin(pixelPlugin);
sprocket->addPlugin(webServerPlugin);
sprocket->addPlugin(webConfigPlugin);
sprocket->addPlugin(webApiPlugin);
sprocket->addPlugin(ircPlugin);
sprocket->addPlugin(mqttPlugin);
network = new WiFiNet(
WIFI_MODE,
STATION_SSID,
STATION_PASSWORD,
AP_SSID,
AP_PASSWORD,
HOSTNAME,
CONNECT_TIMEOUT);
network->connect();
webServerPlugin->server->serveStatic(PIXEL_CONFIG_FILE, SPIFFS, "pixelConfig.json");
webServerPlugin->server->serveStatic(IRC_CONFIG_FILE, SPIFFS, "ircConfig.json");
webServerPlugin->server->serveStatic(MQTT_CONFIG_FILE, SPIFFS, "mqttConfig.json");
sprocket->subscribe("irc/connected", [](String msg) {
if (atoi(msg.c_str()))
{
sprocket->subscribe("irc/log", [](String msg) {
PRINT_MSG(Serial, "CHAT", String("incoming: " + msg).c_str());
webApiPlugin->ws->textAll(msg);
});
sprocket->subscribe("out/chat/log", [](String msg) {
PRINT_MSG(Serial, "CHAT", String("outgoing: " + msg).c_str());
sprocket->publish("irc/sendMessage", msg);
webApiPlugin->ws->textAll("You:"+msg);
});
sprocket->publish("chat/connected", "");
}
});
sprocket->activate();
sprocket->publish("irc/connect","");
}
void loop()
{
sprocket->loop();
yield();
}

56
src/var/mqcatt/main.cpp Normal file
View File

@@ -0,0 +1,56 @@
#include "mqcatt_config.h"
#include <WiFiNet.h>
#include <Sprocket.h>
#include "../../IlluCat.h"
#include <ESPAsyncWebServer.h>
#include <WebServerConfig.h>
#include <WebServerPlugin.h>
#include <WebConfigPlugin.h>
#include <WebApiPlugin.h>
#include <PixelPlugin.h>
#include <MqttPlugin.h>
WiFiNet *network;
Sprocket *sprocket;
WebServerPlugin *webServerPlugin;
WebConfigPlugin *webConfigPlugin;
WebApiPlugin *webApiPlugin;
PixelPlugin *pixelPlugin;
MqttPlugin *mqttPlugin;
void setup()
{
sprocket = new Sprocket({STARTUP_DELAY, SERIAL_BAUD_RATE});
pixelPlugin = new PixelPlugin({LED_STRIP_PIN, LED_STRIP_LENGTH, LED_STRIP_BRIGHTNESS, LED_STRIP_UPDATE_INTERVAL});
mqttPlugin = new MqttPlugin({MQTT_CLIENT_NAME, MQTT_HOST, MQTT_PORT, MQTT_ROOT_TOPIC, MQTT_USER, MQTT_PASS});
webServerPlugin = new WebServerPlugin({WEB_CONTEXT_PATH, WEB_DOC_ROOT, WEB_DEFAULT_FILE, WEB_PORT});
webConfigPlugin = new WebConfigPlugin(webServerPlugin->server);
webApiPlugin = new WebApiPlugin(webServerPlugin->server);
sprocket->addPlugin(pixelPlugin);
sprocket->addPlugin(webServerPlugin);
sprocket->addPlugin(webConfigPlugin);
sprocket->addPlugin(webApiPlugin);
sprocket->addPlugin(mqttPlugin);
network = new WiFiNet(
WIFI_MODE,
STATION_SSID,
STATION_PASSWORD,
AP_SSID,
AP_PASSWORD,
HOSTNAME,
CONNECT_TIMEOUT);
network->connect();
webServerPlugin->server->serveStatic(PIXEL_CONFIG_FILE, SPIFFS, "pixelConfig.json");
webServerPlugin->server->serveStatic(MQTT_CONFIG_FILE, SPIFFS, "config/mqtt.json");
sprocket->activate();
sprocket->publish("pixels/pattern", "1");
}
void loop()
{
sprocket->loop();
yield();
}

View File

@@ -0,0 +1,58 @@
#ifndef __MQCATT_CONFIG__
#define __MQCATT_CONFIG__
// Scheduler config
#define _TASK_SLEEP_ON_IDLE_RUN
#define _TASK_STD_FUNCTION
#define _TASK_PRIORITY
// Chip config
#define SPROCKET_TYPE "ILLUCAT"
#define SERIAL_BAUD_RATE 74880
#define STARTUP_DELAY 5000
// Network config
#define WIFI_MODE 0
#define WIFI_CHANNEL 11
#define AP_SSID "illucat"
#define AP_PASSWORD "illumination"
#define MESH_PREFIX "illucat-mesh"
#define MESH_PASSWORD "th3r31sn0sp00n"
#define STATION_SSID "thobens-416257"
#define STATION_PASSWORD "467304645DB5"
#define HOSTNAME "illucat"
#define CONNECT_TIMEOUT 10000
// config files
#define PIXEL_CONFIG_FILE "/pixelConfig.json"
#define MQTT_CONFIG_FILE "/config/mqtt.json"
// NeoPixel
#define LED_STRIP_PIN D2
#define LED_STRIP_LENGTH 8
#define LED_STRIP_BRIGHTNESS 48
#define LED_STRIP_UPDATE_INTERVAL 200
#define LED_STRIP_DEFAULT_COLOR 100
#define COLOR_CONNECTED LED_STRIP_DEFAULT_COLOR
#define COLOR_NOT_CONNECTED 255
#define LED_STRIP_DEFAULT_PATTERN 1
// OTA config
#define OTA_PORT 8266
#define OTA_PASSWORD ""
// mqtt config
#define MQTT_CLIENT_NAME "illucat"
#define MQTT_HOST "192.168.88.110"
#define MQTT_PORT 1883
#define MQTT_ROOT_TOPIC "wirelos/illucat"
#define MQTT_USER ""
#define MQTT_PASS ""
// WebServer
#define WEB_CONTEXT_PATH "/"
#define WEB_DOC_ROOT "/www"
#define WEB_DEFAULT_FILE "index.html"
#define WEB_PORT 80
#endif

29
src/var/wifi/main.cpp Normal file
View File

@@ -0,0 +1,29 @@
#include "config.h"
#include "WiFiNet.h"
#include "IlluCat.h"
WiFiNet *network;
IlluCat *sprocket;
void setup()
{
sprocket = new IlluCat(
{STARTUP_DELAY, SERIAL_BAUD_RATE},
{WEB_CONTEXT_PATH, WEB_DOC_ROOT, WEB_DEFAULT_FILE, WEB_PORT});
network = new WiFiNet(
SPROCKET_MODE,
STATION_SSID,
STATION_PASSWORD,
AP_SSID,
AP_PASSWORD,
HOSTNAME,
CONNECT_TIMEOUT);
network->connect();
sprocket->activate();
}
void loop()
{
sprocket->loop();
yield();
}

28
src/var/wifiMesh/main.cpp Normal file
View File

@@ -0,0 +1,28 @@
#include "config.h"
#include "Sprocket.h"
#include <MeshNetworkPlugin.cpp>
#include "PixelPlugin.h"
Sprocket *sprocket;
void setup()
{
sprocket = new Sprocket(
{STARTUP_DELAY, SERIAL_BAUD_RATE});
sprocket->addPlugin(new PixelPlugin(
{LED_STRIP_PIN,
LED_STRIP_LENGTH,
LED_STRIP_BRIGHTNESS,
LED_STRIP_UPDATE_INTERVAL}));
sprocket->addPlugin(new MeshNetworkPlugin(
{SPROCKET_MODE, WIFI_CHANNEL,
MESH_PORT, MESH_PREFIX, MESH_PASSWORD,
STATION_SSID, STATION_PASSWORD, HOSTNAME,
MESH_DEBUG_TYPES}));
sprocket->activate();
}
void loop()
{
sprocket->loop();
yield();
}