Skip to content

Commit

Permalink
Remove max LED number constraint from Matrix layout (#1805)
Browse files Browse the repository at this point in the history
  • Loading branch information
Lord-Grey authored Dec 9, 2024
1 parent e8e102c commit 179ee31
Show file tree
Hide file tree
Showing 28 changed files with 231 additions and 76 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Allow to force starting Hyperion in read-only mode (`--readonlyMode`)
- JSON-API: Support to query for a dedicated set of configuration items for a set of instances
- JSON-API: Support to save a dedicated set of configuration items for a set of instances
- JSON-API: Limit update emission frequency: Images (25Hz), raw LED-Colors (40Hz) & LED-Device data (200Hz)
- Effects: Limit the maximum update rate to 200Hz

**JSON-API**
- New subscription support for event updates, i.e. `Suspend, Resume, Idle, idleResume, Restart, Quit`.
Expand All @@ -44,6 +46,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Refactored: Python to enable parallel effect processing under Python 3.12
- Fixed: Python 3.12 crashes (#1747)
- osX Grabber: Use ScreenCaptureKit under macOS 15 and above
- Removed maximum LED number constraint from Matrix layout schema which was not synced with the UI behaviour (#1804)

**JSON-API**
- Refactored JSON-API to ensure consistent authorization behaviour across sessions and single requests with token authorization.
Expand Down
3 changes: 3 additions & 0 deletions effects/candle.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@

sleepTime = float(hyperion.args.get('sleepTime', 0.14))

# Limit update rate
sleepTime = max(hyperion.lowestUpdateInterval(), sleepTime)

candles = hyperion.args.get('candles', "all")
ledlist = hyperion.args.get('ledlist', "1")

Expand Down
4 changes: 4 additions & 0 deletions effects/gif.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
grayscale = bool(hyperion.args.get('grayscale', False))

sleepTime = 1./framesPerSecond

# Limit update rate
sleepTime = max(hyperion.lowestUpdateInterval(), sleepTime)

imageFrameList = []

if imageData:
Expand Down
3 changes: 3 additions & 0 deletions effects/ledtest-seq.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
# Get parameters
sleepTime = float(hyperion.args.get('sleepTime', 0.5))

# Limit update rate
sleepTime = max(hyperion.lowestUpdateInterval(), sleepTime)

def TestRgb( iteration ):

switcher = {
Expand Down
3 changes: 3 additions & 0 deletions effects/ledtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
testleds = hyperion.args.get('testleds', "all")
ledlist = hyperion.args.get('ledlist', "1")

# Limit update rate
sleepTime = max(hyperion.lowestUpdateInterval(), sleepTime)

testlist = ()
if (testleds == "list") and (type(ledlist) is str):
for s in ledlist.split(','):
Expand Down
3 changes: 3 additions & 0 deletions effects/plasma.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
height = hyperion.imageHeight()
sleepTime = float(hyperion.args.get('sleepTime', 0.2))

# Limit update rate
sleepTime = max(hyperion.lowestUpdateInterval(), sleepTime)

def mapto(x, in_min, in_max, out_min, out_max):
return float((x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min)

Expand Down
5 changes: 4 additions & 1 deletion effects/running_dots.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
sleepTime = float(hyperion.args.get('speed', 1.5)) * 0.005
whiteLevel = int(hyperion.args.get('whiteLevel', 0))
lvl = int(hyperion.args.get('colorLevel', 220))

# Limit update rate
sleepTime = max(hyperion.lowestUpdateInterval(), sleepTime)

# check value
# check value
whiteLevel = min( whiteLevel, 254 )
lvl = min( lvl, 255 )

Expand Down
3 changes: 3 additions & 0 deletions effects/shutdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ def setPixel(x,y,rgb):

imageData = bytearray(height * width * (0,0,0))

# Limit update rate
sleepTime = max(hyperion.lowestUpdateInterval(), sleepTime)

# Start the write data loop
if initialBlink:
for i in range(6):
Expand Down
3 changes: 3 additions & 0 deletions effects/sparks.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
color = list(hyperion.args.get('color', (255,255,255)))
randomColor = bool(hyperion.args.get('random-color', False))

# Limit update rate
sleepTime = max(hyperion.lowestUpdateInterval(), sleepTime)

# Check parameters
rotationTime = max(0.1, rotationTime)

Expand Down
5 changes: 4 additions & 1 deletion effects/swirl.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ def getPoint(rand = True ,x = 0.5, y = 0.5):
def getSTime(rt, steps = 360):
rt = float(rt)
sleepTime = max(0.1, rt) / steps


# Limit update rate
sleepTime = max(hyperion.lowestUpdateInterval(), sleepTime)

# adapt sleeptime to hardware
minStepTime= float(hyperion.latchTime)/1000.0
if minStepTime == 0: minStepTime = 0.001
Expand Down
3 changes: 3 additions & 0 deletions effects/traces.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
if minStepTime == 0: minStepTime = 0.001
factor = 1 if sleepTime > minStepTime else int(math.ceil(minStepTime/sleepTime))

# Limit update rate
sleepTime = max(hyperion.lowestUpdateInterval(), sleepTime)

runners = [
{ "i":0, "pos":0, "c":0, "step":9, "lvl":255},
{ "i":1, "pos":0, "c":0, "step":8, "lvl":255},
Expand Down
5 changes: 4 additions & 1 deletion effects/trails.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@
color = list(hyperion.args.get('color', (255,255,255)))
randomise = bool(hyperion.args.get('random', False))
iWidth = hyperion.imageWidth()
iHeight = hyperion.imageHeight()
iHeight = hyperion.imageHeight()

# Limit update rate
sleepTime = max(hyperion.lowestUpdateInterval(), sleepTime)

class trail:
def __init__(self):
Expand Down
5 changes: 4 additions & 1 deletion effects/x-mas.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
sleepTime = float(hyperion.args.get('sleepTime', 1000))/1000.0
length = hyperion.args.get('length', 1)
color1 = hyperion.args.get('color1', (255,255,255))
color2 = hyperion.args.get('color2', (255,0,0))
color2 = hyperion.args.get('color2', (255,0,0))

# Limit update rate
sleepTime = max(hyperion.lowestUpdateInterval(), sleepTime)

# Initialize the led data
i = 0
Expand Down
4 changes: 3 additions & 1 deletion include/api/JsonAPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ class JsonAPI : public API
///
void initialize();

QSharedPointer<JsonCallbacks> getCallBack() const;

public slots:

private slots:
Expand Down Expand Up @@ -82,7 +84,7 @@ private slots:
///
/// Signal emits with the reply message provided with handleMessage()
///
void callbackMessage(QJsonObject);
void callbackReady(QJsonObject);

///
/// Signal emits whenever a JSON-message should be forwarded
Expand Down
4 changes: 3 additions & 1 deletion include/api/JsonCallbacks.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class JsonCallbacks : public QObject
/// @brief Emits whenever a new json mesage callback is ready to send
/// @param The JsonObject message
///
void newCallback(QJsonObject);
void callbackReady(QJsonObject);

private slots:
///
Expand Down Expand Up @@ -182,6 +182,8 @@ private slots:

/// construct callback msg
void doCallback(Subscription::Type cmd, const QVariant& data);
void doCallback(Subscription::Type cmd, const QJsonArray& data);
void doCallback(Subscription::Type cmd, const QJsonObject& data);

Logger *_log;
Hyperion* _hyperion;
Expand Down
2 changes: 2 additions & 0 deletions include/effectengine/Effect.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,6 @@ class Effect : public QThread
QImage _image;
QPainter* _painter;
QVector<QImage> _imageStack;

double _lowestUpdateIntervalInSeconds;
};
49 changes: 25 additions & 24 deletions include/effectengine/EffectModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,28 +21,29 @@ class EffectModule : public QObject

// Wrapper methods for Python interpreter extra buildin methods
static PyMethodDef effectMethods[];
static PyObject* wrapSetColor(PyObject* self, PyObject* args);
static PyObject* wrapSetImage(PyObject* self, PyObject* args);
static PyObject* wrapGetImage(PyObject* self, PyObject* args);
static PyObject* wrapAbort(PyObject* self, PyObject* args);
static PyObject* wrapImageShow(PyObject* self, PyObject* args);
static PyObject* wrapImageLinearGradient(PyObject* self, PyObject* args);
static PyObject* wrapImageConicalGradient(PyObject* self, PyObject* args);
static PyObject* wrapImageRadialGradient(PyObject* self, PyObject* args);
static PyObject* wrapImageSolidFill(PyObject* self, PyObject* args);
static PyObject* wrapImageDrawLine(PyObject* self, PyObject* args);
static PyObject* wrapImageDrawPoint(PyObject* self, PyObject* args);
static PyObject* wrapImageDrawRect(PyObject* self, PyObject* args);
static PyObject* wrapImageDrawPolygon(PyObject* self, PyObject* args);
static PyObject* wrapImageDrawPie(PyObject* self, PyObject* args);
static PyObject* wrapImageSetPixel(PyObject* self, PyObject* args);
static PyObject* wrapImageGetPixel(PyObject* self, PyObject* args);
static PyObject* wrapImageSave(PyObject* self, PyObject* args);
static PyObject* wrapImageMinSize(PyObject* self, PyObject* args);
static PyObject* wrapImageWidth(PyObject* self, PyObject* args);
static PyObject* wrapImageHeight(PyObject* self, PyObject* args);
static PyObject* wrapImageCRotate(PyObject* self, PyObject* args);
static PyObject* wrapImageCOffset(PyObject* self, PyObject* args);
static PyObject* wrapImageCShear(PyObject* self, PyObject* args);
static PyObject* wrapImageResetT(PyObject* self, PyObject* args);
static PyObject* wrapSetColor (PyObject *self, PyObject *args);
static PyObject* wrapSetImage (PyObject *self, PyObject *args);
static PyObject* wrapGetImage (PyObject *self, PyObject *args);
static PyObject* wrapAbort (PyObject *self, PyObject *args);
static PyObject* wrapImageShow (PyObject *self, PyObject *args);
static PyObject* wrapImageLinearGradient (PyObject *self, PyObject *args);
static PyObject* wrapImageConicalGradient (PyObject *self, PyObject *args);
static PyObject* wrapImageRadialGradient (PyObject *self, PyObject *args);
static PyObject* wrapImageSolidFill (PyObject *self, PyObject *args);
static PyObject* wrapImageDrawLine (PyObject *self, PyObject *args);
static PyObject* wrapImageDrawPoint (PyObject *self, PyObject *args);
static PyObject* wrapImageDrawRect (PyObject *self, PyObject *args);
static PyObject* wrapImageDrawPolygon (PyObject *self, PyObject *args);
static PyObject* wrapImageDrawPie (PyObject *self, PyObject *args);
static PyObject* wrapImageSetPixel (PyObject *self, PyObject *args);
static PyObject* wrapImageGetPixel (PyObject *self, PyObject *args);
static PyObject* wrapImageSave (PyObject *self, PyObject *args);
static PyObject* wrapImageMinSize (PyObject *self, PyObject *args);
static PyObject* wrapImageWidth (PyObject *self, PyObject *args);
static PyObject* wrapImageHeight (PyObject *self, PyObject *args);
static PyObject* wrapImageCRotate (PyObject *self, PyObject *args);
static PyObject* wrapImageCOffset (PyObject *self, PyObject *args);
static PyObject* wrapImageCShear (PyObject *self, PyObject *args);
static PyObject* wrapImageResetT (PyObject *self, PyObject *args);
static PyObject* wrapLowestUpdateInterval (PyObject* self, PyObject* args);
};
12 changes: 12 additions & 0 deletions include/hyperion/Hyperion.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

// stl includes
#include <list>
#include <chrono>

// QT includes
#include <QString>
Expand All @@ -11,6 +12,7 @@
#include <QJsonValue>
#include <QJsonArray>
#include <QMap>
#include <QElapsedTimer>

// hyperion-utils includes
#include <utils/Image.h>
Expand Down Expand Up @@ -604,4 +606,14 @@ private slots:
/// Boblight instance
BoblightServer* _boblightServer;
#endif

QElapsedTimer _imageTimer; // Timer for controlling image emission frequency
QElapsedTimer _rawLedDataTimer; // Timer for controlling rawLedColors emission frequency
QElapsedTimer _ledDeviceDataTimer; // Timer for controlling LedDevice data emission frequency
qint64 _lastImageEmission; // Last timestamp of image signal emission
qint64 _lastRawLedDataEmission; // Last timestamp of rawLedColors signal emission
qint64 _lastLedDeviceDataEmission; // Last timestamp of ledDeviceData signal emission
std::chrono::milliseconds _imageEmissionInterval;
std::chrono::milliseconds _rawLedDataEmissionInterval;
std::chrono::milliseconds _ledDeviceDataEmissionInterval;
};
16 changes: 9 additions & 7 deletions libsrc/api/JsonAPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ JsonAPI::JsonAPI(QString peerAddress, Logger *log, bool localConnection, QObject
_jsonCB = QSharedPointer<JsonCallbacks>(new JsonCallbacks( _log, _peerAddress, parent));
}

QSharedPointer<JsonCallbacks> JsonAPI::getCallBack() const
{
return _jsonCB;
}

void JsonAPI::initialize()
{
// init API, REQUIRED!
Expand All @@ -97,9 +102,6 @@ void JsonAPI::initialize()
// listen for killed instances
connect(_instanceManager, &HyperionIManager::instanceStateChanged, this, &JsonAPI::handleInstanceStateChange);

// pipe callbacks from subscriptions to parent
connect(_jsonCB.data(), &JsonCallbacks::newCallback, this, &JsonAPI::callbackMessage);

// notify hyperion about a jsonMessageForward
if (_hyperion != nullptr)
{
Expand Down Expand Up @@ -1537,7 +1539,7 @@ void JsonAPI::sendSuccessReply(const JsonApiCommand& cmd)

void JsonAPI::sendSuccessReply(const QString &command, int tan, InstanceCmd::Type isInstanceCmd)
{
emit callbackMessage(getBasicCommandReply(true, command, tan , isInstanceCmd));
emit callbackReady(getBasicCommandReply(true, command, tan , isInstanceCmd));
}

void JsonAPI::sendSuccessDataReply(const QJsonValue &infoData, const JsonApiCommand& cmd)
Expand Down Expand Up @@ -1572,7 +1574,7 @@ void JsonAPI::sendSuccessDataReplyWithError(const QJsonValue &infoData, const QS
reply["errorData"] = errorsArray;
}

emit callbackMessage(reply);
emit callbackReady(reply);
}

void JsonAPI::sendErrorReply(const QString &error, const JsonApiCommand& cmd)
Expand Down Expand Up @@ -1601,7 +1603,7 @@ void JsonAPI::sendErrorReply(const QString &error, const QStringList& errorDetai
reply["errorData"] = errorsArray;
}

emit callbackMessage(reply);
emit callbackReady(reply);
}

void JsonAPI::sendNewRequest(const QJsonValue &infoData, const JsonApiCommand& cmd)
Expand All @@ -1621,7 +1623,7 @@ void JsonAPI::sendNewRequest(const QJsonValue &infoData, const QString &command,

request["info"] = infoData;

emit callbackMessage(request);
emit callbackReady(request);
}

void JsonAPI::sendNoAuthorization(const JsonApiCommand& cmd)
Expand Down
Loading

0 comments on commit 179ee31

Please sign in to comment.