def test_sequence_relative_to_now(): seq = AnimationSequence( start="-30m", stop="+30m", every="8m", ) assert seq.start == datetime(2021, 11, 19, 20, 4, 17, tzinfo=tzutc()) assert seq.stop == datetime(2021, 11, 19, 21, 4, 17, tzinfo=tzutc()) assert seq.recurrence.every == "8m" assert seq.recurrence.frequency == MINUTELY assert seq.recurrence.interval == 8 assert seq.recurrence.duration == relativedelta(minutes=+8, seconds=-1) assert list(seq.get_timeranges_isoformat()) == [ "2021-11-19T20:04:17+00:00/2021-11-19T20:12:16+00:00", "2021-11-19T20:12:17+00:00/2021-11-19T20:20:16+00:00", "2021-11-19T20:20:17+00:00/2021-11-19T20:28:16+00:00", "2021-11-19T20:28:17+00:00/2021-11-19T20:36:16+00:00", "2021-11-19T20:36:17+00:00/2021-11-19T20:44:16+00:00", "2021-11-19T20:44:17+00:00/2021-11-19T20:52:16+00:00", "2021-11-19T20:52:17+00:00/2021-11-19T21:00:16+00:00", "2021-11-19T21:00:17+00:00/2021-11-19T21:08:16+00:00", ]
def test_sequence_isodate(): seq = AnimationSequence( start="2021-11-15T02:12:05Z", stop="2021-11-15T02:37:36Z", every="3min", mode=SequencingMode.CUMULATIVE, ) assert seq.start == datetime(2021, 11, 15, 2, 12, 5, tzinfo=tzutc()) assert seq.stop == datetime(2021, 11, 15, 2, 37, 36, tzinfo=tzutc()) assert seq.mode == SequencingMode.CUMULATIVE assert seq.recurrence.every == "3min" assert seq.recurrence.frequency == MINUTELY assert seq.recurrence.interval == 3 assert seq.recurrence.duration == relativedelta(minutes=+3, seconds=-1) assert list(seq.get_timeranges_isoformat()) == [ "2021-11-15T02:12:05+00:00/2021-11-15T02:12:05+00:00", "2021-11-15T02:12:05+00:00/2021-11-15T02:15:05+00:00", "2021-11-15T02:12:05+00:00/2021-11-15T02:18:05+00:00", "2021-11-15T02:12:05+00:00/2021-11-15T02:21:05+00:00", "2021-11-15T02:12:05+00:00/2021-11-15T02:24:05+00:00", "2021-11-15T02:12:05+00:00/2021-11-15T02:27:05+00:00", "2021-11-15T02:12:05+00:00/2021-11-15T02:30:05+00:00", "2021-11-15T02:12:05+00:00/2021-11-15T02:33:05+00:00", "2021-11-15T02:12:05+00:00/2021-11-15T02:36:05+00:00", "2021-11-15T02:12:05+00:00/2021-11-15T02:39:05+00:00", ]
def test_sequence_relative_with_now(): seq = AnimationSequence( start="-7d", stop="now", every="1d", ) assert seq.start == datetime(2021, 11, 12, 20, 34, 17, tzinfo=tzutc()) assert seq.stop == datetime(2021, 11, 19, 20, 34, 17, tzinfo=tzutc()) assert seq.recurrence.every == "1d" assert seq.recurrence.frequency == DAILY assert seq.recurrence.interval == 1 assert seq.recurrence.duration == relativedelta(days=+1, seconds=-1) assert list(seq.get_timeranges_isoformat()) == [ "2021-11-12T20:34:17+00:00/2021-11-13T20:34:16+00:00", "2021-11-13T20:34:17+00:00/2021-11-14T20:34:16+00:00", "2021-11-14T20:34:17+00:00/2021-11-15T20:34:16+00:00", "2021-11-15T20:34:17+00:00/2021-11-16T20:34:16+00:00", "2021-11-16T20:34:17+00:00/2021-11-17T20:34:16+00:00", "2021-11-17T20:34:17+00:00/2021-11-18T20:34:16+00:00", "2021-11-18T20:34:17+00:00/2021-11-19T20:34:16+00:00", "2021-11-19T20:34:17+00:00/2021-11-20T20:34:16+00:00", ]
def playdemo(): """ Run demo on `play.grafana.org`. Synopsis:: grafanimate --scenario=playdemo --output=./animations """ logger.info("Running scenario playdemo") return AnimationScenario( grafana_url="https://play.grafana.org/", dashboard_uid="000000012", sequences=[ AnimationSequence( start=datetime(2021, 11, 14, 2, 0, 0), # Produce video with reasonable duration to explore different rendering options. stop=datetime(2021, 11, 14, 4, 16, 36), # Produce very short video. # stop=datetime(2021, 11, 14, 2, 16, 36), every="5min", mode=SequencingMode.CUMULATIVE, ), ], )
def ldi_nye_2018_2019(): """ LDI, New Year's Eve 2018/2019 Synopsis:: grafanimate --grafana-url=https://daq.example.org/grafana --dashboard-uid=1aOmc1sik --scenario=ldi_nye_2018_2019 --output=./animations """ logger.info("Running scenario ldi_nye_2018_2019") return [ AnimationSequence(start=datetime(2018, 12, 31, 15, 0, 0), stop=datetime(2018, 12, 31, 20, 0, 0), every="30min"), AnimationSequence(start=datetime(2018, 12, 31, 20, 0, 0), stop=datetime(2018, 12, 31, 23, 0, 0), every="10min"), AnimationSequence(start=datetime(2018, 12, 31, 23, 0, 0), stop=datetime(2019, 1, 1, 1, 0, 0), every="5min"), AnimationSequence(start=datetime(2019, 1, 1, 1, 0, 0), stop=datetime(2019, 1, 1, 4, 0, 0), every="10min"), AnimationSequence(start=datetime(2019, 1, 1, 4, 0, 0), stop=datetime(2019, 1, 1, 9, 0, 0), every="30min"), ]
def ldi_all(): """ Luftdaten.info, all Synopsis:: grafanimate --grafana-url=https://daq.example.org/grafana --dashboard-uid=1aOmc1sik --scenario=ldi_all --output=./animations """ logger.info("Running scenario ldi_all") return [ # LDI, ramp-up AnimationSequence(start=datetime(2015, 10, 1), stop=datetime(2017, 1, 1), every="monthly"), # LDI, growth AnimationSequence(start=datetime(2017, 1, 1), stop=datetime.now(), every="weekly"), ]
def cdc_maps(): """ DWD CDC, temperatur-sonne-and-niederschlag-karten Synopsis:: grafanimate --grafana-url=https://daq.example.org/grafana --dashboard-uid=DLOlE_Rmz --scenario=cdc_maps --output=./animations """ logger.info("Running scenario cdc_maps") return AnimationSequence(start=datetime(2018, 3, 6, 5, 0, 0), stop=datetime(2018, 3, 10, 23, 59, 59), every="hourly")
def ldi_with_gaps(): """ Luftdaten.info, growth Synopsis:: grafanimate --grafana-url=https://daq.example.org/grafana --dashboard-uid=1aOmc1sik --scenario=ldi_with_gaps --output=./animations """ logger.info("Running scenario ldi_with_gaps") return [ # LDI, ramp-up AnimationSequence(start=datetime(2015, 10, 1), stop=datetime(2017, 1, 1), every="monthly"), # LDI, growth, with gap at 2018-04-29 - 2018-12-20 # TODO: Detect empty data from datasource through Grafana Sidecar and skip respective images. AnimationSequence(start=datetime(2017, 1, 1), stop=datetime(2018, 6, 5), every="weekly"), # LDI, until now AnimationSequence(start=datetime(2018, 12, 20), stop=datetime.now(), every="weekly"), ]
def uba_ldi_dwd_maps(): """ Labor: Studio / UBA/LDI/DWD-Studio [dev!] Synopsis:: grafanimate --grafana-url=https://daq.example.org/grafana --dashboard-uid=of6c9qlmk --scenario=uba_ldi_dwd_maps --output=./animations """ logger.info("Running scenario uba_ldi_dwd_maps") return AnimationSequence( start=datetime(2018, 10, 6, 5, 0, 0), stop=datetime(2018, 10, 10, 23, 59, 59), every="hourly" )
def test_scenario_basic(): scenario = AnimationScenario( grafana_url="https://daq.example.org/grafana/", dashboard_uid="foobar", sequences=[ AnimationSequence( start="2021-11-14T15:20:05Z", stop="2021-11-14T15:45:36Z", every="5min", mode=SequencingMode.WINDOW, ), AnimationSequence( start="2021-11-15T02:12:05Z", stop="2021-11-15T02:37:36Z", every="3 minutes 2 seconds", mode=SequencingMode.CUMULATIVE, ), ], ) assert len(scenario.sequences) == 2
def ir_sensor_svg_pixmap(): """ start: 2018-08-14 03:16:00 stop: 2018-08-14 03:16:36 Synopsis:: grafanimate --grafana-url=https://daq.example.org/grafana --dashboard-uid=acUXbj_mz --scenario=ir_sensor_svg_pixmap --output=./animations """ logger.info("Running scenario ir_sensor_svg_pixmap") return AnimationSequence( start=datetime(2018, 8, 14, 3, 16, 0), stop=datetime(2018, 8, 14, 3, 16, 36), every="secondly" )
def test_sequence_datetime(): seq = AnimationSequence( start=datetime(2021, 11, 14, 2, 0, 0), stop=datetime(2021, 11, 14, 2, 16, 36), every="5min", ) assert seq.start == datetime(2021, 11, 14, 2, 0, 0) assert seq.stop == datetime(2021, 11, 14, 2, 16, 36) assert seq.mode == SequencingMode.WINDOW assert seq.recurrence.every == "5min" assert seq.recurrence.frequency == MINUTELY assert seq.recurrence.interval == 5 assert seq.recurrence.duration == relativedelta(minutes=+5, seconds=-1) assert list(seq.get_timeranges_isoformat()) == [ "2021-11-14T02:00:00/2021-11-14T02:04:59", "2021-11-14T02:05:00/2021-11-14T02:09:59", "2021-11-14T02:10:00/2021-11-14T02:14:59", "2021-11-14T02:15:00/2021-11-14T02:19:59", ]
def test_sequence_epoch(): seq = AnimationSequence( start=1637091011, stop=1637091911, every="4m5s", mode=SequencingMode.CUMULATIVE, ) assert seq.start == datetime(2021, 11, 16, 19, 30, 11, tzinfo=timezone.utc) assert seq.stop == datetime(2021, 11, 16, 19, 45, 11, tzinfo=timezone.utc) assert seq.mode == SequencingMode.CUMULATIVE assert seq.recurrence.every == "4m5s" assert seq.recurrence.frequency == MINUTELY assert seq.recurrence.interval == 4 assert seq.recurrence.duration == relativedelta(minutes=+4, seconds=+4) assert list(seq.get_timeranges_isoformat()) == [ "2021-11-16T19:30:11+00:00/2021-11-16T19:30:11+00:00", "2021-11-16T19:30:11+00:00/2021-11-16T19:34:11+00:00", "2021-11-16T19:30:11+00:00/2021-11-16T19:38:11+00:00", "2021-11-16T19:30:11+00:00/2021-11-16T19:42:11+00:00", "2021-11-16T19:30:11+00:00/2021-11-16T19:46:11+00:00", ]
def playdemo_advanced(): """ Run demo on `play.grafana.org`, demonstrating different flavors of timestamps. Synopsis:: grafanimate --scenario=playdemo_advanced --output=./animations """ logger.info("Running scenario playdemo") return AnimationScenario( grafana_url="https://play.grafana.org/", dashboard_uid="000000012", sequences=[ AnimationSequence( start=datetime(2021, 11, 14, 2, 0, 0), stop=datetime(2021, 11, 14, 2, 16, 36), every="5min", mode=SequencingMode.CUMULATIVE, ), AnimationSequence( start="2021-11-15T02:12:05Z", stop="2021-11-15T02:37:36Z", every="3min", mode=SequencingMode.CUMULATIVE, ), AnimationSequence( start=1637091011, stop=1637091911, every="4m5s", mode=SequencingMode.CUMULATIVE, ), AnimationSequence( start="-30m", stop="+30m", every="5m", mode=SequencingMode.CUMULATIVE, ), AnimationSequence( start="-14d", stop="start+7d", every="1d", mode=SequencingMode.CUMULATIVE, ), AnimationSequence( start="-14d", stop="now", every="1d", mode=SequencingMode.CUMULATIVE, ), ], )
def run(self, sequence: AnimationSequence): if not isinstance(sequence, AnimationSequence): return self.log("Starting animation: {}".format(sequence)) frame: AnimationFrame = None for frame in sequence.get_frames(): # logger.info("=" * 42) # Render image. image = self.render(frame) # Build item model. item = munchify({ "meta": { "grafana": self.grafana, "scenario": self.options["scenario"], "dashboard": self.dashboard_uid, "every": frame.timerange.recurrence.every, }, "data": { "start": frame.timerange.start, "stop": frame.timerange.stop, "image": image, }, "frame": frame, }) if self.options["exposure-time"] > 0: logger.info("Waiting for {} seconds (exposure time)".format( self.options["exposure-time"])) time.sleep(self.options["exposure-time"]) yield item self.log("Animation finished")