OpenLightingProject / ola

The Open Lighting Architecture - The Travel Adaptor for the Lighting Industry
https://www.openlighting.org/ola/
Other
647 stars 205 forks source link

Resend dmx values every x seconds? #1313

Closed doits closed 7 years ago

doits commented 7 years ago

I'm using olad with an EurolitePro USB device and it worked fine. Olad runs on my raspberry pi and I recently upgraded to rasbpian stretch which seems it also updated olad (to 0.10.3). I don't know what version of olad was installed before the update.

In my setup my LED stripes and controllers are often shut off completely (AC power is cut off) and when they regain power they don't remember their last dmx values by themselves but have to get them again.

Before the update, when the AC power came back to my controllers and LED stripes they got the recent dmx values from ola. I assume the dmx values were sent periodically over the wire by ola.

Now they stay off/black until I manually change the dmx values in olad. It seems olad does not send the old values periodically and I have to trigger the resend manually.

Is there a way to make my setup work? Maybe to resend current dmx values every x seconds?

If it is not possible through ola directly, I could write a shell script which reads current values and resends them again as a work around (something like ola -u 0 --get-current-dmx-values | ola -u 0 --set-dmx-values), but I did not find such options by looking through the man pages.

peternewman commented 7 years ago

See the discussion in https://github.com/OpenLightingProject/ola/issues/1288 .

Can you remember which version of Raspberry Pi you were on before? Was OLA installed with apt-get, or from somewhere else?

What are (and were) you using to control them/set the values in olad?

We've talked about a filter to do what you want, but that's a feature request for a future version of OLA ( https://github.com/OpenLightingProject/ola/issues/280 ).

To send in data (from STDIN or via other means), we have: http://docs.openlighting.org/ola/man/man1/ola_streaming_client.1.html

We don't currently have a CLI tool to extract DMX from the looks of things, although the Python examples cover both cases: https://github.com/OpenLightingProject/ola/tree/master/python/examples

You could write something in Python to essentially cache and retransmit old frames, but you'll still need to deal with some edge cases, e.g. if a frame is missed on the Rx side, does it resend the old data, what if the frame is just slow arriving. It could potentially make for a rather lumpy fade. You'll also want to receive on one universe and transmit on a second so you don't get a feedback loop.

peternewman commented 7 years ago

Finally, this will help you work out if you're no longer sending data, or if the Eurolite Pro is just getting bored and stopping sending: http://docs.openlighting.org/ola/man/man1/ola_uni_stats.1.html

doits commented 7 years ago

@peternewman thanks for your feedback.

Can you remember which version of Raspberry Pi you were on before? Was OLA installed with apt-get, or from somewhere else?

It was from apt-get, according to https://packages.debian.org/jessie/ola it was 0.9.1

What are (and were) you using to control them/set the values in olad?

Simply from console: ola_set_dmx -u 0 -d 255,90,...

Before the update, those settings persisted even after a power cycle of the controller and led stripes (not the eurolite usb device nor the raspberry pi, those stayed on).

You could write something in Python to essentially cache and retransmit old frames, but you'll still need to deal with some edge cases, e.g. if a frame is missed on the Rx side, does it resend the old data, what if the frame is just slow arriving. It could potentially make for a rather lumpy fade. You'll also want to receive on one universe and transmit on a second so you don't get a feedback loop.

Since I am only using it for on/off scenarios yet (e.g. set a persistent color, no fading at all), my use case is rather simple (for now).

I'll look into the documentation you provided and see if I come up with a solution. I'm planning to get my hands dirty with ola in the next month anyway, since I want to implement custom fading etc., and the python scripts look like to be a good starting point.

peternewman commented 7 years ago

Hmm, I wasn't aware of us making changes that would impact that stuff, certainly not intentionally, since 0.9.1. Although that is quite some time ago so there's a chance.

A rather cludgy solution, what about just doing a bash while loop to repeatedly send the data using ola_set_dmx?

In terms of patterns, you might also like this: https://github.com/nomis52/ola-pixel-patterns

peternewman commented 7 years ago

Actually I've just looked at 0.9.1 and I can see we used to just send continuously periodically for some interfaces, whereas now almost everything just sends a frame when you give it a frame. Which I think should give a smoother result overall, but does lead to some edge cases like you've got.

doits commented 7 years ago

FYI, i finally managed to resend old dmx values every X seconds by using this script:

#!/usr/bin/env python
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Library General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

from __future__ import print_function
from array import array
from sys import stderr
from ola.ClientWrapper import ClientWrapper

UPDATE_INTERVAL = 3000
UNIVERSE        = 0
INITIAL_DATA    = [227,81,14,227,81,14,68,23,10,227,81,14,227,81,14,227,81,14,227,81,14,227,81,14]

class SimpleDmxSender(object):
  def __init__(self, universe, initial_data, update_interval, client_wrapper):
    self._universe        = 0
    self._update_interval = update_interval
    self._data            = array('B')
    self._wrapper         = client_wrapper
    self._client          = client_wrapper.Client()

    for value in initial_data:
      self._data.append(value)

    self._wrapper.AddEvent(self._update_interval, self.UpdateDmx)
    self._client.RegisterUniverse(self._universe, self._client.REGISTER, self.NewData)

    print('SimpleDmxSender init done')

  def UpdateDmx(self):
    self._client.SendDmx(self._universe, self._data, self.DmxSent)
    self._wrapper.AddEvent(self._update_interval, self.UpdateDmx)

  def DmxSent(self, status):
    if not status.Succeeded():
      print('Error: %s' % status.message, file=stderr)

  def NewData(self, data):
    self._data = data

if __name__ == '__main__':
  wrapper = ClientWrapper()
  controller = SimpleDmxSender(UNIVERSE, INITIAL_DATA, UPDATE_INTERVAL, wrapper)
  print('Running wrapper ...')
  wrapper.Run()

It resends data every 3 seconds and listens for changes, too. So if another source changes the data, it will pick it up and resend the new data.