Merge pull request #777 from zandegran/master

Nanoleaf Aurora Support
This commit is contained in:
Rick164 2019-05-03 09:03:53 +02:00 committed by GitHub
commit 8aff3cb9b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 256 additions and 0 deletions

View File

@ -38,6 +38,7 @@ SET(Leddevice_HEADERS
${CURRENT_SOURCE_DIR}/LedDeviceFile.h
${CURRENT_SOURCE_DIR}/LedDeviceFadeCandy.h
${CURRENT_SOURCE_DIR}/LedDeviceUdp.h
${CURRENT_SOURCE_DIR}/LedDeviceAurora.h
${CURRENT_SOURCE_DIR}/LedDeviceUdpRaw.h
${CURRENT_SOURCE_DIR}/LedUdpDevice.h
${CURRENT_SOURCE_DIR}/LedDeviceHyperionUsbasp.h
@ -64,6 +65,7 @@ SET(Leddevice_SOURCES
${CURRENT_SOURCE_DIR}/LedDeviceFile.cpp
${CURRENT_SOURCE_DIR}/LedDeviceFadeCandy.cpp
${CURRENT_SOURCE_DIR}/LedDeviceUdp.cpp
${CURRENT_SOURCE_DIR}/LedDeviceAurora.cpp
${CURRENT_SOURCE_DIR}/LedDeviceUdpRaw.cpp
${CURRENT_SOURCE_DIR}/LedUdpDevice.cpp
${CURRENT_SOURCE_DIR}/LedDeviceHyperionUsbasp.cpp

View File

@ -0,0 +1,187 @@
// Local-Hyperion includes
#include "LedDeviceAurora.h"
#include <netdb.h>
#include <assert.h>
// jsoncpp includes
#include <json/json.h>
// qt includes
#include <QEventLoop>
#include <QNetworkReply>
#define ROOT_ROUTE ""
#define EFFECTS_ROUTE "effects"
#define URL_FORMAT "http://%1:16021/api/v1/%2/%3"
#define EXT_MODE_STRING "{\"write\" : {\"command\" : \"display\", \"animType\" : \"extControl\"}}"
#define PANELLAYOUT_KEY "panelLayout"
#define PANELCOUNT_KEY "numPanels"
#define PANELID_KEY "panelId"
#define POSITIONDATA_KEY "positionData"
#define UDPPORT_KEY "streamControlPort"
#define RHYTHM_KEY "rhythm"
#define RHYTHM_CONNECTED_KEY "rhythmConnected"
struct addrinfo vints, *serverinfo, *pt;
//char udpbuffer[1024];
int sockfp;
int update_num;
LedDeviceAurora::LedDeviceAurora(const std::string& output, const std::string& key) {
manager = new QNetworkAccessManager();
std::string hostname = output;
std::string port;
Json::Reader reader;
Json::FastWriter writer;
// Read Panel count and panel Ids
QByteArray response = get(QString::fromStdString(hostname), QString::fromStdString(key), ROOT_ROUTE);
Json::Value json;
if (!reader.parse(QString(response).toStdString(), json)) {
throw std::runtime_error("No Layout found");
}
//Debug
// Json::FastWriter fastWriter;
// std::cout << fastWriter.write(json);
Json::Value rhythmJson = json[RHYTHM_KEY];
json = json[PANELLAYOUT_KEY];
panelCount = json[PANELCOUNT_KEY].asUInt();
Json::Value positionDataJson = json[POSITIONDATA_KEY];
// Loop over all children.
for (Json::ValueIterator it = positionDataJson.begin(); it != positionDataJson.end() && panelIds.size() < panelCount; it++) {
Json::Value panel = *it;
int panelId = panel[PANELID_KEY].asUInt();
panelIds.push_back(panelId);
}
// Check if we found enough lights.
if ((panelIds.size() != panelCount) || (panelIds.size() != panelCount-1 && rhythmJson[RHYTHM_CONNECTED_KEY].asBool())) {
throw std::runtime_error("Not enough pannels found");
}else {
std::cout << "All panel Ids found: "<< panelIds.size()<<std::endl;
}
// Set Aurora to UDP Mode
QByteArray modeResponse = changeMode(QString::fromStdString(hostname), QString::fromStdString(key), EFFECTS_ROUTE);
Json::Value configJson;
if (!reader.parse(QString(modeResponse).toStdString(), configJson)) {
throw std::runtime_error("Could not change Mode token ");
}
//std::cout << fastWriter.write(configJson);
// Get UDP port
port = std::to_string(configJson[UDPPORT_KEY].asUInt());
//std::cout << "output " << output << " hostname " << hostname << " port " << port <<std::endl;
int rv;
memset(&vints, 0, sizeof vints);
vints.ai_family = AF_UNSPEC;
vints.ai_socktype = SOCK_DGRAM;
if ((rv = getaddrinfo(hostname.c_str() , port.c_str(), &vints, &serverinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
assert(rv==0);
}
// loop through all the results and make a socket
for(pt = serverinfo; pt != NULL; pt = pt->ai_next) {
if ((sockfp = socket(pt->ai_family, pt->ai_socktype,
pt->ai_protocol)) == -1) {
perror("talker: socket");
continue;
}
break;
}
if (pt == NULL) {
fprintf(stderr, "talker: failed to create socket\n");
assert(pt!=NULL);
}
//std::cout << "Started successfully ";
}
QString LedDeviceAurora::getUrl(QString host, QString token, QString route) {
return QString(URL_FORMAT).arg(host).arg(token).arg(route);
}
QByteArray LedDeviceAurora::get(QString host, QString token, QString route) {
QString url = getUrl(host, token, route);
// Perfrom request
QNetworkRequest request(url);
QNetworkReply* reply = manager->get(request);
// Connect requestFinished signal to quit slot of the loop.
QEventLoop loop;
loop.connect(reply, SIGNAL(finished()), SLOT(quit()));
// Go into the loop until the request is finished.
loop.exec();
// Read all data of the response.
QByteArray response = reply->readAll();
// Free space.
reply->deleteLater();
// Return response
return response;
}
QByteArray LedDeviceAurora::putJson(QString url, QString json) {
// Perfrom request
QNetworkRequest request(url);
QNetworkReply* reply = manager->put(request, json.toUtf8());
// Connect requestFinished signal to quit slot of the loop.
QEventLoop loop;
loop.connect(reply, SIGNAL(finished()), SLOT(quit()));
// Go into the loop until the request is finished.
loop.exec();
// Read all data of the response.
QByteArray response = reply->readAll();
// Free space.
reply->deleteLater();
// Return response
return response;
}
QByteArray LedDeviceAurora::changeMode(QString host, QString token, QString route) {
QString url = getUrl(host, token, route);
QString jsondata(EXT_MODE_STRING); //Enable UDP Mode
return putJson(url, jsondata);
}
LedDeviceAurora::~LedDeviceAurora()
{
delete manager;
}
int LedDeviceAurora::write(const std::vector<ColorRgb> & ledValues)
{
uint udpBufferSize = panelCount * 7 + 1;
char udpbuffer[udpBufferSize];
update_num++;
update_num &= 0xf;
int i=0;
int panelCounter = 0;
udpbuffer[i++] = panelCount;
for (const ColorRgb& color : ledValues)
{
if (i<udpBufferSize) {
udpbuffer[i++] = panelIds[panelCounter++ % panelCount];
udpbuffer[i++] = 1; // No of Frames
udpbuffer[i++] = color.red;
udpbuffer[i++] = color.green;
udpbuffer[i++] = color.blue;
udpbuffer[i++] = 0; // W not set manually
udpbuffer[i++] = 1; // currently fixed at value 1 which corresponds to 100ms
}
if(panelCounter > panelCount) {
break;
}
//printf ("c.red %d sz c.red %d\n", color.red, sizeof(color.red));
}
sendto(sockfp, udpbuffer, i, 0, pt->ai_addr, pt->ai_addrlen);
return 0;
}
int LedDeviceAurora::switchOff()
{
return 0;
}

View File

@ -0,0 +1,59 @@
#pragma once
// Leddevice includes
#include <leddevice/LedDevice.h>
// Qt includes
#include <QObject>
#include <QString>
#include <QNetworkAccessManager>
#include <QTimer>
///
/// Implementation of the LedDevice that write the led-colors to an
/// ASCII-textfile('/home/pi/LedDevice.out')
///
class LedDeviceAurora : public LedDevice
{
public:
///
/// Constructs the test-device, which opens an output stream to the file
///
LedDeviceAurora(const std::string& output, const std::string& key);
///
/// Destructor of this test-device
///
virtual ~LedDeviceAurora();
///
/// Writes the given led-color values to the output stream
///
/// @param ledValues The color-value per led
///
/// @return Zero on success else negative
///
virtual int write(const std::vector<ColorRgb> & ledValues);
/// Switch the leds off
virtual int switchOff();
private:
/// The outputstream
// std::ofstream _ofs;
// QNetworkAccessManager object for sending requests.
QNetworkAccessManager* manager;
// the number of leds (needed when switching off)
size_t panelCount;
/// Array of the pannel ids.
std::vector<unsigned int> panelIds;
QByteArray get(QString host, QString token, QString route);
QByteArray putJson(QString url, QString json);
QByteArray changeMode(QString host, QString token, QString route);
///
/// @param route
///
/// @return the full URL of the request.
///
QString getUrl(QString host, QString token, QString route);
};

View File

@ -40,6 +40,7 @@
#include "LedDeviceAtmo.h"
#include "LedDeviceAdalightApa102.h"
#include "LedDeviceAtmoOrb.h"
#include "LedDeviceAurora.h"
#ifdef ENABLE_WS2812BPWM
#include "LedDeviceWS2812b.h"
@ -319,6 +320,13 @@ LedDevice * LedDeviceFactory::construct(const Json::Value & deviceConfig)
const unsigned maxPacket = deviceConfig["maxpacket"].asInt();
device = new LedDeviceUdp(output, rate, protocol, maxPacket);
}
else if (type == "aurora")
{
const std::string output = deviceConfig["output"].asString();
const std::string key = deviceConfig["key"].asString();
LedDeviceAurora* deviceAurora = new LedDeviceAurora(output, key);
device = deviceAurora;
}
else if (type == "udpraw")
{
const std::string output = deviceConfig["output"].asString();

0
libsrc/leddevice/LedDeviceUdp.cpp Normal file → Executable file
View File

0
libsrc/leddevice/LedDeviceUdp.h Normal file → Executable file
View File