Compare commits

..

2 Commits

Author SHA1 Message Date
root
6cdf28a761 CCC Backup. Unkown changes 2021-04-22 19:37:30 +02:00
5436c007d2 Moved button read to slowloop 2020-06-22 23:45:10 +02:00
28 changed files with 49 additions and 151 deletions

0
.clang-format Normal file → Executable file
View File

0
.gitignore vendored Normal file → Executable file
View File

0
.gitmodules vendored Normal file → Executable file
View File

0
.travis.yml Normal file → Executable file
View File

14
.vscode/extensions.json vendored Normal file → Executable file
View File

@ -1,7 +1,7 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
]
}
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
]
}

7
.vscode/settings.json vendored Normal file → Executable file
View File

@ -33,12 +33,7 @@
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"typeinfo": "cpp",
"complex": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"iomanip": "cpp",
"iostream": "cpp"
"typeinfo": "cpp"
},
"editor.formatOnSave": true,
}

0
CAD/LED Cylinder.ipt Normal file → Executable file
View File

0
CAD/LED ring.ipt Normal file → Executable file
View File

0
CAD/STL/LED Cylinder.stl Normal file → Executable file
View File

0
CAD/STL/SharpHolder.stl Normal file → Executable file
View File

0
CAD/STL/bulb base.stl Normal file → Executable file
View File

0
CAD/SharpHolder.ipt Normal file → Executable file
View File

0
CAD/base.ipt Normal file → Executable file
View File

0
CAD/bulb base.ipt Normal file → Executable file
View File

0
CAD/lamp.iam Normal file → Executable file
View File

0
CAD/mid plastig.ipt Normal file → Executable file
View File

0
CAD/shade.ipt Normal file → Executable file
View File

21
README.md Normal file → Executable file
View File

@ -8,15 +8,17 @@ An esp8266 powered **IKEA Tvärfot** with a Neopixel ring and a proximity sensor
![](https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fwww.ikea.com%2Fbe%2Ffr%2Fimages%2Fproducts%2Ftvaerfot-table-lamp-black-white__0772756_PE756088_S5.JPG%3Ff%3Dxxs&f=1&nofb=1)
## LED strip
## Writing a configuration
### LED strip
A NeoPixel strip with 7 diods is used for the light and connects to **D8**. This could really be any DIO. For this change the variable ***ledPin*** in ***main.cpp***.
To power the LED strip connect it to the 5V supply. The power output on the ESP8266 may not be enough if connected to the *raw* pin when powering from the USB port. The recommendation is to power it in parallel to the ESP by e.g. supplying the ESP with power on the raw pin while using the same for powering the LED.
## Distance Sensor
### Distance Sensor
To measure the distance an IR based sensor from Sharp (2Y0A21) is used. This sensor is connected to the analog input **A0**. This is the only analog input on the ESP8266.
To power the Sharp sensor connect it to any free 3.3V pin on the ESP.
## Writing a configuration
### Configuration
Open a Serial Monitor at baudrate 9600 and paste the following json configuration adapted to your needs.
Before sending press the on board button "flash" or connect a button to D0. You will now have 10s to send the configuration. The onboard LED will light up as long as the board reads Serial input. If successful the new configuration should be shown in the terminal.
@ -30,7 +32,6 @@ It is also possible to send the same json configuration on mqtt using topic *lig
"mqttuser": "mymqtt_user",
"mqttpass": "7j%!fs#",
"mqttport": "1883",
"guestureEnabled" : "true"
}
```
@ -56,15 +57,6 @@ An identical json package is both sent and received to set and get the status of
### Configuration topic
See *Writing a configuration*. This can also be done using mqtt at topic ***light/bedlamp/relay/0/config***
### Debug topic
Meant for debugging there is a topic ***light/bedlamp/debug***. This topic will output:
* The configuration of the lamp at boot
* Uptime (s) is sent repeatedly at every *state* update (default each 120s)
* All incoming topics and payloads
### Guesture Enable topic
Topic to activate or deactivate guestures for controlling the lamp ***light/bedlamp/guestureenabled/set***. Payload **1** or **0**.
## Home Assistant
Adjust the name and topics to suite your configuration
```
@ -73,9 +65,6 @@ Adjust the name and topics to suite your configuration
schema: json
state_topic: light/bedlamp/relay/0
command_topic: light/bedlamp/relay/0/set
availability_topic: light/bedlamp/status
payload_available: 1
payload_not_available: 0
brightness: true
rgb: true
```

BIN
firmware.bin Executable file

Binary file not shown.

0
include/README Normal file → Executable file
View File

5
include/config.h Normal file → Executable file
View File

@ -13,7 +13,6 @@ public:
char mqttUser[10];
char mqttPass[20];
int mqttPort;
bool gestureEnabled;
uint8_t brightness;
std::array<uint8_t, 3> color;
} Data;
@ -22,10 +21,6 @@ public:
OutTopic,
InTopic,
ConfigTopic,
AvailabilityTopic,
DebugTopic,
InGuestureEnabled,
OutGuestureEnabled,
};
static Config& Instance();

0
include/myled.h Normal file → Executable file
View File

0
lib/README Normal file → Executable file
View File

11
platformio.ini Normal file → Executable file
View File

@ -13,16 +13,9 @@ platform = espressif8266
board = esp12e
framework = arduino
[env:esp8266 OTA Right]
[env:esp8266 OTA]
platform = espressif8266
board = esp12e
framework = arduino
upload_protocol = espota
upload_port = bedlamp-right
[env:esp8266 OTA Left]
platform = espressif8266
board = esp12e
framework = arduino
upload_protocol = espota
upload_port = bedlamp-left
upload_port = bedlamp-philip

15
src/config.cpp Normal file → Executable file
View File

@ -65,20 +65,7 @@ String Config::getMqttTopic(MqttTopic topic)
return String("light/" + String(data.hostname) + "/relay/0/set");
break;
case (MqttTopic::ConfigTopic):
return String("light/" + String(data.hostname) + "/config");
break;
case (MqttTopic::AvailabilityTopic):
return String("light/" + String(data.hostname) + "/status");
break;
case (MqttTopic::DebugTopic):
return String("light/" + String(data.hostname) + "/debug");
break;
case (MqttTopic::InGuestureEnabled):
return String("light/" + String(data.hostname) +
"/guestureenabled/set");
break;
case (MqttTopic::OutGuestureEnabled):
return String("light/" + String(data.hostname) + "/guestureenabled");
return String("light/" + String(data.hostname) + "/relay/0/config");
break;
}
return {};

108
src/main.cpp Normal file → Executable file
View File

@ -22,8 +22,6 @@ const int sensorPin = A0;
const int ledPin = D8;
const int ledCount = 7;
const int publishInterval = 120;
Config& config = Config::Instance();
EasyButton button(buttonPin);
@ -35,7 +33,7 @@ PubSubClient mqttClient(wifiClient);
WebOTA webOTA(82);
Ticker tickerPublishStatus;
Ticker tickerLedStatus, tickerMqttCyclic, tickerMqttReconnect;
typedef struct {
float distance; // Distance in mm
@ -55,7 +53,6 @@ void setConfig(String jsonConfig)
String mqttUser = obj["mqttuser"];
String mqttPass = obj["mqttpass"];
int mqttPort = obj["mqttport"];
bool gestureEnabled = obj["gestureEnabled"];
Serial.printf("Parsed hostname: %s, ssid: %s, pass: %s\n",
hostname.c_str(),
ssid.c_str(),
@ -75,8 +72,6 @@ void setConfig(String jsonConfig)
sizeof(config.data.mqttPass));
config.data.mqttPort = mqttPort;
config.data.gestureEnabled = gestureEnabled;
config.write();
Serial.println("rebooting...");
@ -84,29 +79,6 @@ void setConfig(String jsonConfig)
}
}
String configToString()
{
DynamicJsonDocument doc(1024);
auto jsonConfig = doc["config"];
jsonConfig["hostname"] = config.data.hostname;
jsonConfig["ssid"] = config.data.ssid;
jsonConfig["pass"] = config.data.pass;
jsonConfig["mqttserver"] = config.data.mqttServer;
jsonConfig["mqttuser"] = config.data.mqttUser;
jsonConfig["mqttpass"] = config.data.mqttPass;
jsonConfig["mqttport"] = config.data.mqttPort;
jsonConfig["guestureenabled"] = config.data.gestureEnabled;
jsonConfig["brightness"] = config.data.brightness;
JsonArray color = jsonConfig.createNestedArray("color");
color.add(config.data.color.at(0));
color.add(config.data.color.at(1));
color.add(config.data.color.at(2));
String output;
serializeJson(doc, output);
return output;
}
void checkSerial()
{
String s = Serial.readString();
@ -125,7 +97,9 @@ void onPressed()
unsigned long t = millis();
// Stop all tickers
tickerPublishStatus.detach();
tickerLedStatus.detach();
tickerMqttCyclic.detach();
tickerMqttReconnect.detach();
while (millis() - t < 10000)
{
@ -138,25 +112,12 @@ void onPressed()
void mqttPublishState()
{
if (mqttClient.connected())
{
mqttClient.publish(
config.getMqttTopic(Config::MqttTopic::OutTopic).c_str(),
myLed.get().c_str());
mqttClient.publish(
config.getMqttTopic(Config::MqttTopic::AvailabilityTopic).c_str(),
"1");
mqttClient.publish(
config.getMqttTopic(Config::MqttTopic::OutGuestureEnabled).c_str(),
String(config.data.gestureEnabled).c_str());
auto uptime = millis() / 1000;
mqttClient.publish(
config.getMqttTopic(Config::MqttTopic::DebugTopic).c_str(),
String("{ \"uptime\":" + String(uptime) + "}").c_str());
}
}
void mqttConnect()
void mqttReconnect()
{
if (!mqttClient.connected())
{
@ -171,43 +132,31 @@ void mqttConnect()
config.getMqttTopic(Config::MqttTopic::InTopic).c_str());
mqttClient.subscribe(
config.getMqttTopic(Config::MqttTopic::ConfigTopic).c_str());
mqttClient.subscribe(
config.getMqttTopic(Config::MqttTopic::InGuestureEnabled)
.c_str());
} else
{
Serial.printf("failed, rc=%d\n", mqttClient.state());
Serial.print("failed, rc=");
Serial.print(mqttClient.state());
Serial.println(" try again in 5 seconds");
tickerMqttReconnect.once(5, mqttReconnect);
}
}
}
void mqttCallback(char* topic, byte* payload, unsigned int length)
{
const String sTopic(topic);
String msg;
msg.concat(reinterpret_cast<char*>(payload), length);
String msg(reinterpret_cast<char const*>(payload));
Serial.printf("Message arrived [%s] \n", topic);
Serial.println(msg.c_str());
if (sTopic == config.getMqttTopic(Config::InTopic))
if (String(topic) == config.getMqttTopic(Config::InTopic))
{
myLed.set(msg);
mqttPublishState();
} else if (sTopic == config.getMqttTopic(Config::ConfigTopic))
} else if (String(topic) == config.getMqttTopic(Config::ConfigTopic))
{
setConfig(msg);
} else if (sTopic == config.getMqttTopic(Config::InGuestureEnabled))
{
config.data.gestureEnabled = (msg == "1");
config.write();
mqttClient.publish(
config.getMqttTopic(Config::MqttTopic::OutGuestureEnabled).c_str(),
String(config.data.gestureEnabled).c_str());
}
mqttClient.publish(
config.getMqttTopic(Config::MqttTopic::DebugTopic).c_str(),
String("{\"received\": { \"" + sTopic + "\": " + msg + " } }").c_str());
}
void offCallback()
@ -240,7 +189,6 @@ void setup()
config.load();
myLed.setState(
MyLed::State({config.data.color, config.data.brightness, true}));
WiFi.setAutoReconnect(true);
WiFi.begin(config.data.ssid, config.data.pass);
WiFi.hostname(config.data.hostname);
Serial.print("Connecting");
@ -262,12 +210,9 @@ void setup()
ArduinoOTA.setHostname(config.data.hostname);
ArduinoOTA.begin();
tickerPublishStatus.attach(publishInterval, mqttPublishState);
mqttConnect();
mqttClient.publish(
config.getMqttTopic(Config::MqttTopic::DebugTopic).c_str(),
configToString().c_str());
tickerLedStatus.attach(120, mqttPublishState);
tickerMqttCyclic.attach(60 * 5, mqttReconnect);
mqttReconnect();
webOTA.setup(&WiFi);
}
@ -289,7 +234,7 @@ SensorData getDist()
// https://global.sharp/products/device/lineup/data/pdf/datasheet/gp2y0a21yk_e.pdf
const int maxVal = 780; // 60 mm
const int minVal = 173; // 800 mm
const int maxValidDist = 480;
const int maxValidDist = 610;
const int minValidDist = 70;
long dist = map(analogRead(sensorPin), maxVal, minVal, 60, 800);
@ -299,7 +244,7 @@ SensorData getDist()
float normalizedDistance =
(static_cast<float>(dist) - static_cast<float>(minValidDist)) /
static_cast<float>(maxValidDist - minValidDist);
// Serial.printf("Dist: %d, normalized: %f\n", dist, normalizedDistance);
// Serial.printf("Norm dist: %f\n", normalizedDistance);
return {.distance = static_cast<float>(dist),
.distanceNormalized = normalizedDistance,
@ -316,7 +261,7 @@ void evalDist(SensorData data)
static float lastDist = data.distance;
const float stillThreshold = 15.0f; // Distance in mm
const float stillThreshold = 20.0f; // Distance in mm
const float releaseThreshold =
70.0f; // If value increases more than this it is considered a release
@ -381,17 +326,19 @@ void evalDist(SensorData data)
void slowLoop()
{
if (config.data.gestureEnabled)
if (WiFi.status() != WL_CONNECTED)
{
SensorData data = getDist();
evalDist(data);
Serial.println("WiFi connection lost. Trying to reconnect...");
WiFi.reconnect();
}
button.read();
SensorData data = getDist();
evalDist(data);
myLed.run();
if (!mqttClient.loop())
mqttConnect();
mqttClient.loop();
webOTA.run();
}
@ -400,7 +347,6 @@ void loop()
unsigned long t = millis();
static unsigned long lastT = t;
button.read();
if (t - lastT > 50)
{
lastT = t;

19
src/myled.cpp Normal file → Executable file
View File

@ -2,10 +2,8 @@
#include <ArduinoJson.h>
#include <limits>
namespace {
const float minBrightness = 0.05;
const float minBrightness = 0.2;
}
MyLed::MyLed(int ledPin, int ledCount, bool effects)
@ -58,7 +56,7 @@ void MyLed::toggle()
void MyLed::set(String jsonState)
{
DynamicJsonDocument doc(2048);
DynamicJsonDocument doc(1024);
deserializeJson(doc, jsonState);
JsonObject obj = doc.as<JsonObject>();
Serial.println(jsonState.c_str());
@ -109,7 +107,7 @@ MyLed::State MyLed::getState()
void MyLed::setBrightness(float brightness)
{
brightness = min(max(minBrightness, brightness), 1.0f);
brightness = max(minBrightness, brightness);
if (_useEffects)
{
@ -153,13 +151,8 @@ void MyLed::registerOffCallback(CallbackFunc callback)
void MyLed::apply()
{
uint8_t a = 254;
_strip.fill(
_strip.Color(min(static_cast<uint8_t>(_color.at(0) * _brightness),
std::numeric_limits<uint8_t>::max()),
min(static_cast<uint8_t>(_color.at(1) * _brightness),
std::numeric_limits<uint8_t>::max()),
min(static_cast<uint8_t>(_color.at(2) * _brightness),
std::numeric_limits<uint8_t>::max())));
_strip.fill(_strip.Color(static_cast<uint8_t>(_color.at(0) * _brightness),
static_cast<uint8_t>(_color.at(1) * _brightness),
static_cast<uint8_t>(_color.at(2) * _brightness)));
_strip.show();
}

0
test/README Normal file → Executable file
View File