2015-02-18 01:45:39 +01:00
|
|
|
from django.utils.timezone import now
|
|
|
|
|
2016-09-17 22:26:23 +02:00
|
|
|
from ..utils.projector import ProjectorElement
|
2015-09-05 14:58:10 +02:00
|
|
|
from .config import config
|
2015-02-18 01:45:39 +01:00
|
|
|
from .exceptions import ProjectorException
|
2016-09-18 22:14:24 +02:00
|
|
|
from .models import Projector
|
2015-06-12 21:08:57 +02:00
|
|
|
|
2015-02-18 01:45:39 +01:00
|
|
|
|
|
|
|
class Clock(ProjectorElement):
|
|
|
|
"""
|
|
|
|
Clock on the projector.
|
|
|
|
"""
|
|
|
|
name = 'core/clock'
|
|
|
|
|
|
|
|
|
|
|
|
class Countdown(ProjectorElement):
|
|
|
|
"""
|
|
|
|
Countdown on the projector.
|
|
|
|
|
|
|
|
To start the countdown write into the config field:
|
|
|
|
|
|
|
|
{
|
2015-09-14 23:16:31 +02:00
|
|
|
"status": "running",
|
2015-02-18 01:45:39 +01:00
|
|
|
"countdown_time": <timestamp>,
|
|
|
|
}
|
|
|
|
|
2015-09-14 23:16:31 +02:00
|
|
|
The timestamp is a POSIX timestamp (seconds) calculated from client
|
2015-02-18 01:45:39 +01:00
|
|
|
time, server time offset and countdown duration (countdown_time = now -
|
|
|
|
serverTimeOffset + duration).
|
|
|
|
|
2015-09-05 14:58:10 +02:00
|
|
|
To stop the countdown set the countdown time to the current value of the
|
2015-02-18 01:45:39 +01:00
|
|
|
countdown (countdown_time = countdown_time - now + serverTimeOffset)
|
|
|
|
and set status to "stop".
|
|
|
|
|
|
|
|
To reset the countdown (it is not a reset in a functional way) just
|
2015-09-14 23:16:31 +02:00
|
|
|
change the countdown time. The status value remains "stop".
|
2015-02-18 01:45:39 +01:00
|
|
|
|
2015-09-14 23:16:31 +02:00
|
|
|
Do not forget to send values for additional keywords like "stable" if
|
|
|
|
you do not want to use the default.
|
2015-09-05 14:58:10 +02:00
|
|
|
|
2015-09-14 23:16:31 +02:00
|
|
|
The countdown backend supports an extra keyword "default".
|
|
|
|
|
|
|
|
{
|
|
|
|
"default": <seconds>
|
|
|
|
}
|
|
|
|
|
|
|
|
This is used for the internal reset method if the countdown is coupled
|
|
|
|
with the list of speakers. The default of this default value can be
|
|
|
|
customized in OpenSlides config 'projector_default_countdown'.
|
|
|
|
|
|
|
|
Use additional keywords to control view behavior like "visable" and
|
|
|
|
"label". These keywords are not handles by the backend.
|
2015-02-18 01:45:39 +01:00
|
|
|
"""
|
|
|
|
name = 'core/countdown'
|
|
|
|
|
2016-02-27 20:25:06 +01:00
|
|
|
def check_data(self):
|
2015-09-05 14:58:10 +02:00
|
|
|
self.validate_config(self.config_entry)
|
2015-02-18 01:45:39 +01:00
|
|
|
|
2015-09-05 14:58:10 +02:00
|
|
|
@classmethod
|
|
|
|
def validate_config(cls, config_data):
|
|
|
|
"""
|
|
|
|
Raises ProjectorException if the given data are invalid.
|
|
|
|
"""
|
|
|
|
if not isinstance(config_data.get('countdown_time'), (int, float)):
|
2015-11-21 00:00:31 +01:00
|
|
|
raise ProjectorException('Invalid countdown time. Use integer or float.')
|
2015-09-05 14:58:10 +02:00
|
|
|
if config_data.get('status') not in ('running', 'stop'):
|
2015-11-21 00:00:31 +01:00
|
|
|
raise ProjectorException("Invalid status. Use 'running' or 'stop'.")
|
2015-09-05 14:58:10 +02:00
|
|
|
if config_data.get('default') is not None and not isinstance(config_data.get('default'), int):
|
2015-11-21 00:00:31 +01:00
|
|
|
raise ProjectorException('Invalid default value. Use integer.')
|
2015-09-05 14:58:10 +02:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def control(cls, action, projector_id=1, index=0):
|
|
|
|
"""
|
|
|
|
Starts, stops or resets the countdown with the given index on the
|
|
|
|
given projector.
|
|
|
|
|
|
|
|
Action must be 'start', 'stop' or 'reset'.
|
|
|
|
"""
|
|
|
|
if action not in ('start', 'stop', 'reset'):
|
|
|
|
raise ValueError("Action must be 'start', 'stop' or 'reset', not {}.".format(action))
|
|
|
|
|
|
|
|
projector_instance = Projector.objects.get(pk=projector_id)
|
2015-09-06 13:28:25 +02:00
|
|
|
projector_config = {}
|
2015-09-05 14:58:10 +02:00
|
|
|
found = False
|
2015-09-06 13:28:25 +02:00
|
|
|
for key, value in projector_instance.config.items():
|
|
|
|
if value['name'] == cls.name:
|
2015-09-05 14:58:10 +02:00
|
|
|
if index == 0:
|
|
|
|
try:
|
2015-09-06 13:28:25 +02:00
|
|
|
cls.validate_config(value)
|
2015-09-05 14:58:10 +02:00
|
|
|
except ProjectorException:
|
|
|
|
# Do not proceed if the specific procjector config data is invalid.
|
|
|
|
# The variable found remains False.
|
|
|
|
break
|
|
|
|
found = True
|
2015-09-06 13:28:25 +02:00
|
|
|
if action == 'start' and value['status'] == 'stop':
|
|
|
|
value['status'] = 'running'
|
|
|
|
value['countdown_time'] = now().timestamp() + value['countdown_time']
|
|
|
|
elif action == 'stop' and value['status'] == 'running':
|
|
|
|
value['status'] = 'stop'
|
|
|
|
value['countdown_time'] = value['countdown_time'] - now().timestamp()
|
2015-09-05 14:58:10 +02:00
|
|
|
elif action == 'reset':
|
2015-09-06 13:28:25 +02:00
|
|
|
value['status'] = 'stop'
|
|
|
|
value['countdown_time'] = value.get('default', config['projector_default_countdown'])
|
2015-09-05 14:58:10 +02:00
|
|
|
else:
|
|
|
|
index += -1
|
2015-09-06 13:28:25 +02:00
|
|
|
projector_config[key] = value
|
2015-09-05 14:58:10 +02:00
|
|
|
if found:
|
|
|
|
projector_instance.config = projector_config
|
|
|
|
projector_instance.save()
|
|
|
|
|
2015-02-18 01:45:39 +01:00
|
|
|
|
|
|
|
class Message(ProjectorElement):
|
|
|
|
"""
|
|
|
|
Short message on the projector. Rendered as overlay.
|
|
|
|
"""
|
|
|
|
name = 'core/message'
|
|
|
|
|
2016-02-27 20:25:06 +01:00
|
|
|
def check_data(self):
|
2015-02-18 01:45:39 +01:00
|
|
|
if self.config_entry.get('message') is None:
|
2015-11-21 00:00:31 +01:00
|
|
|
raise ProjectorException('No message given.')
|