Hallo,
Ich wollte noch mal mein Thema von vor einem Jahr aufwärmen. Ich bin nun etwas weiter gekommen. Immer noch als Prototype auf dem Breadboard, aber immerhin.
Der Plan: Ein Photon von Particle.io soll als Controller über WiFi dienen. Ein OLED Display(Adafruit SPI) soll eine scrollbare Liste von Aktoren eines Raumes darstellen und schalten(Togglen) können. Der Schalter wird vermutlich ein Encoder. Jedes Device legt dann für sich fest, wie es ge"toggelt" wird. Das Dingen soll in einem Schaltergehäuse eingebaut werden und mit einem PIR Sensor o.ä ausgerüstet sein, damit das Teil auch schlafen geht.
Stand:
- Breadboard steht
- Der Photon liesst jede 10 Sekunden eine JSON Liste aus einem Raum macht daraus dann eine Liste aus Objekten und speichert den Zustand(On/Off)
- Diese Liste zeigt er derzeit im OLED untereinander an
- Wenn der Aktor "on" ist, wird derzeit der Eintrag im Display invertiert
Was noch zu tun wäre:
Derzeit werden die Devices im Loop aktualisiert. Ich dachte mir, dass man nur beim Start (später auch WakeUp) einmal alle Geräte aktualisiert. Die Architektur des Photon unterstütz, dass man sich eine Art Subscription eines Dienstes einrichten kann oder aber einen solchen zur verfügung stellt. Ich würde gerne meine Objekte in dem Controller Code direkt mit den Devices im FHEM "verbinden". Das heisst, dass die Geräte bei einer Statusänderung selbstständig aus FHEM den aktuellen Status zum Photon pushen. Gibt es so etwas? Oder welches Modul würde dafür in Frage kommen.
Falls jemand daran interessiert ist, diese kleine Bastelei mitzumachen, ich bin offen. Kann auch mit einem (etwas älteren) Spark Core(der Vorgänger) für kleines Geld aushelfen.
Hier noch etwas Details, das Fritzing und mal ein Foto.
Die jsonlist2 habe ich mittels Filter auf das wichtigste reduziert:
{
"Arg":"room=Wohnzimmer STATE",
"Results": [
{
"Name":"WZ.Essen",
"Internals": { "STATE": "off" }
},
{
"Name":"WZ.Esstisch",
"Internals": { "STATE": "off" }
},
{
"Name":"WZ.Fernsehen",
"Internals": { "STATE": "off" }
},
{
"Name":"WZ.Media",
"Internals": { "STATE": "off" }
},
{
"Name":"WZ.Pfette",
"Internals": { "STATE": "off" }
},
{
"Name":"WZ.Sky",
"Internals": { "STATE": "off" }
},
{
"Name":"WZ.Stehlampe",
"Internals": { "STATE": "on" }
} ],
"totalResultsReturned":7
}
Mein C++ ist leider nicht so besonders, daher benötigt der Code wohl noch etwas Zuwendung. Ist derzeit auch alles in einer Klasse, sollte aber noch aufgeteilt werden.
// This #include statement was automatically added by the Particle IDE.
//#include "Device.h"
// This #include statement was automatically added by the Particle IDE.
#include "HttpClient/HttpClient.h"
// This #include statement was automatically added by the Particle IDE.
#include "SparkJson/SparkJson.h"
// This #include statement was automatically added by the Particle IDE.
#include "Adafruit_SSD1306/Adafruit_SSD1306.h"
#undef min
#undef max
#undef swap
#include <map>
/*********************************************************************
This is an example for our Monochrome OLEDs based on SSD1306 drivers
Pick one up today in the adafruit shop!
------> http://www.adafruit.com/category/63_98
This example is for a 128x64 size display using I2C to communicate
3 pins are required to interface (2 I2C and one reset)
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, check license.txt for more information
All text above, and the splash screen must be included in any redistribution
*********************************************************************/
#define OLED_DC D3
#define OLED_CS D4
#define OLED_RESET D5
Adafruit_SSD1306 display(OLED_DC, OLED_RESET, OLED_CS);
typedef struct {
const char* Name;
bool on;
const char* state;
const char* toggle;
} Dev;
#define LOGO16_GLCD_HEIGHT 16
#define LOGO16_GLCD_WIDTH 16
#if (SSD1306_LCDHEIGHT != 64)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif
/**
* Declaring the variables.
*/
unsigned int nextTime = 0; // Next time to contact the server
HttpClient http;
// Headers currently need to be set at init, useful for API keys etc.
http_header_t headers[] = {
// { "Content-Type", "application/json" },
// { "Accept" , "application/json" },
{ "Accept" , "*/*"},
{ NULL, NULL } // NOTE: Always terminate headers will NULL
};
http_request_t request;
http_response_t response;
//DynamicJsonBuffer jsonBuffer;
Dev roomDevices[8];
//Dev roomDevs[8];
//StaticJsonBuffer<600> jsonBuffer;
int uptLed = D7;
int iline = 0;
char json[] = "{\"Arg\":\"room=Wohnzimmer STATE\", \"Results\": [{\"Name\":\"WZ.Essen\", \"Internals\": { \"STATE\": \"on\" } }, {\"Name\":\"WZ.Esstisch\", \"Internals\": { \"STATE\": \"off\" } }, {\"Name\":\"WZ.Fernsehen\", \"Internals\": { \"STATE\": \"off\" } }, {\"Name\":\"WZ.Media\", \"Internals\": { \"STATE\": \"off\" } }, {\"Name\":\"WZ.Pfette\", \"Internals\": { \"STATE\": \"off\" } }, {\"Name\":\"WZ.Sky\", \"Internals\": { \"STATE\": \"off\" } }, {\"Name\":\"WZ.Stehlampe\", \"Internals\": { \"STATE\": \"off\" } } ], \"totalResultsReturned\":7 }";
void setup()
{
//Time.zone(+1);
Serial.begin(9600);
display.begin(SSD1306_SWITCHCAPVCC, 0x3D);
pinMode(uptLed, OUTPUT);
display.display();
}
void loop()
{
if (nextTime > millis()) {
return;
}
Serial.println();
Serial.println("Application>\tStart of Loop.");
// Request path and body can be set at runtime or at setup.
request.hostname = "fhempi.fritz.box";
request.port = 8084;
request.path = "/fhem?cmd=jsonlist2%20room=Wohnzimmer%20STATE&XHR=1";
// The library also supports sending a body with your request:
//request.body = "{\"key\":\"value\"}";
// Get request
http.get(request, response, headers);
Serial.print("Application>\tResponse status: ");
Serial.println(response.status);
strcpy(json, response.body.c_str());
digitalWrite(uptLed, HIGH);
delay(50);
digitalWrite(uptLed, LOW);
delay(30);
digitalWrite(uptLed, HIGH);
delay(50);
digitalWrite(uptLed, LOW);
updateDevices(json);
nextTime = millis() + 500;
}
void updateDevices( char* p_json){
//DynamicJsonBuffer jsonBuffer;
StaticJsonBuffer<2000> jsonBuffer;
Serial.println(p_json);
JsonObject& root = jsonBuffer.parseObject(p_json);
JsonArray& results = root["Results"];
int i = 0;
if (!root.success()) {
Serial.println("parseObject() failed");
return;
}
for(int j=0;j<7;j++){
JsonObject& dev = results[j];
const char* nme = dev["Name"];
//const char* sta = dev["Internals"]["STATE"];
roomDevices[j].Name = nme;
roomDevices[j].state = dev["Internals"]["STATE"].as<const char*>();
}
display.clearDisplay();
display.setTextSize(1);
display.setCursor(3,0);
for(int a=1;a<8;a++)
{
display.setTextColor(WHITE);
if (strcmp(roomDevices[a-1].state,"off")!=0){
display.setTextColor(BLACK, WHITE);
}
display.print(roomDevices[a-1].Name);
display.setCursor(3,a*10);
}
display.display();
Serial.println("Display updated");
}