MythTV  master
zmclient.cpp
Go to the documentation of this file.
1 /*
2  zmclient.cpp
3 */
4 
5 #include <unistd.h>
6 
7 // qt
8 #include <QTimer>
9 
10 //myth
11 #include "mythcontext.h"
12 #include "mythdialogbox.h"
13 #include <mythdate.h>
14 #include "mythmainwindow.h"
15 #include "mythlogging.h"
16 
17 //zoneminder
18 #include "zmclient.h"
19 #include "zmminiplayer.h"
20 
21 // the protocol version we understand
22 #define ZM_PROTOCOL_VERSION "11"
23 
24 #define BUFFER_SIZE (2048*1536*3)
25 
27  : QObject(nullptr),
28  m_retryTimer(new QTimer(this))
29 {
30  setObjectName("ZMClient");
32 
34 }
35 
37 
39 {
40  if (!m_zmclient)
41  m_zmclient = new ZMClient;
42  return m_zmclient;
43 }
44 
46 {
47  QString zmserver_host;
48 
49  zmserver_host = gCoreContext->GetSetting("ZoneMinderServerIP", "");
50  int zmserver_port = gCoreContext->GetNumSetting("ZoneMinderServerPort", -1);
51 
52  // don't try to connect if we don't have a valid host or port
53  if (zmserver_host.isEmpty() || zmserver_port == -1)
54  {
55  LOG(VB_GENERAL, LOG_INFO, "ZMClient: no valid IP or port found for mythzmserver");
56  return false;
57  }
58 
59  return ZMClient::get()->connectToHost(zmserver_host, zmserver_port);
60 }
61 
62 bool ZMClient::connectToHost(const QString &lhostname, unsigned int lport)
63 {
64  QMutexLocker locker(&m_socketLock);
65 
66  m_hostname = lhostname;
67  m_port = lport;
68 
69  m_bConnected = false;
70  int count = 0;
71  do
72  {
73  ++count;
74 
75  LOG(VB_GENERAL, LOG_INFO,
76  QString("Connecting to zm server: %1:%2 (try %3 of 2)")
77  .arg(m_hostname).arg(m_port).arg(count));
78  if (m_socket)
79  {
80  m_socket->DecrRef();
81  m_socket = nullptr;
82  }
83 
84  m_socket = new MythSocket();
85 
87  {
88  m_socket->DecrRef();
89  m_socket = nullptr;
90  }
91  else
92  {
93  m_zmclientReady = true;
94  m_bConnected = true;
95  }
96 
97  usleep(999999);
98 
99  } while (count < 2 && !m_bConnected);
100 
101  if (!m_bConnected)
102  {
103  if (GetNotificationCenter())
104  {
105  ShowNotificationError(tr("Can't connect to the mythzmserver") , "MythZoneMinder",
106  tr("Is it running? "
107  "Have you set the correct IP and port in the settings?"));
108  }
109  }
110 
111  // check the server uses the same protocol as us
113  {
114  m_zmclientReady = false;
115  m_bConnected = false;
116  }
117 
118  if (m_bConnected)
120 
121  return m_bConnected;
122 }
123 
124 bool ZMClient::sendReceiveStringList(QStringList &strList)
125 {
126  QStringList origStrList = strList;
127 
128  bool ok = false;
129  if (m_bConnected)
130  ok = m_socket->SendReceiveStringList(strList);
131 
132  if (!ok)
133  {
134  LOG(VB_GENERAL, LOG_NOTICE, "Connection to mythzmserver lost");
135 
137  {
138  LOG(VB_GENERAL, LOG_ERR, "Re-connection to mythzmserver failed");
139  return false;
140  }
141 
142  // try to resend
143  strList = origStrList;
144  ok = m_socket->SendReceiveStringList(strList);
145  if (!ok)
146  {
147  m_bConnected = false;
148  return false;
149  }
150  }
151 
152  // sanity check
153  if (strList.empty())
154  {
155  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
156  return false;
157  }
158 
159  // the server sends "UNKNOWN_COMMAND" if it did not recognise the command
160  if (strList[0] == "UNKNOWN_COMMAND")
161  {
162  LOG(VB_GENERAL, LOG_ERR, "Somethings is getting passed to the server "
163  "that it doesn't understand");
164  return false;
165  }
166 
167  // the server sends "ERROR" if it failed to process the command
168  if (strList[0].startsWith("ERROR"))
169  {
170  LOG(VB_GENERAL, LOG_ERR,
171  QString("The server failed to process the command. "
172  "The error was:- \n\t\t\t%1").arg(strList[0]));
173  return false;
174  }
175 
176  // we should get "OK" from the server if everything is OK
177  return strList[0] == "OK";
178 }
179 
181 {
182  QMutexLocker locker(&m_commandLock);
183 
184  QStringList strList("HELLO");
185  if (!sendReceiveStringList(strList))
186  {
187  LOG(VB_GENERAL, LOG_ERR, QString("Server didn't respond to 'HELLO'!!"));
188 
189  ShowOkPopup(tr("The mythzmserver didn't respond to our request "
190  "to get the protocol version!!"));
191  return false;
192  }
193 
194  // sanity check
195  if (strList.size() < 2)
196  {
197  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
198  return false;
199  }
200 
201  if (strList[1] != ZM_PROTOCOL_VERSION)
202  {
203  LOG(VB_GENERAL, LOG_ERR,
204  QString("Protocol version mismatch (plugin=%1, mythzmserver=%2)")
205  .arg(ZM_PROTOCOL_VERSION, strList[1]));
206 
207  ShowOkPopup(QString("The mythzmserver uses protocol version %1, "
208  "but this client only understands version %2. "
209  "Make sure you are running compatible versions of "
210  "both the server and plugin.")
211  .arg(strList[1], ZM_PROTOCOL_VERSION));
212  return false;
213  }
214 
215  LOG(VB_GENERAL, LOG_INFO,
216  QString("Using protocol version %1").arg(ZM_PROTOCOL_VERSION));
217  return true;
218 }
219 
221 {
222  // Reset the flag
223  m_zmclientReady = false;
224  m_bConnected = false;
225 
226  // Retry to connect. . . Maybe the user restarted mythzmserver?
228 }
229 
231 {
232  QMutexLocker locker(&m_socketLock);
233 
234  if (m_socket)
236 
237  m_zmclientReady = false;
238  m_bConnected = false;
239 }
240 
242 {
244 
245  m_zmclient = nullptr;
246 
247  if (m_socket)
248  {
249  m_socket->DecrRef();
250  m_socket = nullptr;
251  m_zmclientReady = false;
252  }
253 
254  delete m_retryTimer;
255 }
256 
257 void ZMClient::getServerStatus(QString &status, QString &cpuStat, QString &diskStat)
258 {
259  QMutexLocker locker(&m_commandLock);
260 
261  QStringList strList("GET_SERVER_STATUS");
262  if (!sendReceiveStringList(strList))
263  return;
264 
265  // sanity check
266  if (strList.size() < 4)
267  {
268  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
269  return;
270  }
271 
272  status = strList[1];
273  cpuStat = strList[2];
274  diskStat = strList[3];
275 }
276 
278 {
279  QMutexLocker clocker(&m_commandLock);
280 
281  QStringList strList("GET_MONITOR_STATUS");
282  if (!sendReceiveStringList(strList))
283  return;
284 
285  // sanity check
286  if (strList.size() < 2)
287  {
288  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
289  return;
290  }
291 
292  bool bOK = false;
293  int monitorCount = strList[1].toInt(&bOK);
294  if (!bOK)
295  {
296  LOG(VB_GENERAL, LOG_ERR,
297  "ZMClient received bad int in getMonitorStatus()");
298  return;
299  }
300 
301  QMutexLocker locker(&m_listLock);
302 
303  for (int x = 0; x < monitorCount; x++)
304  {
305  int monID = strList[x * 7 + 2].toInt();
306 
307  if (m_monitorMap.contains(monID))
308  {
309  Monitor *mon = m_monitorMap.find(monID).value();
310  mon->name = strList[x * 7 + 3];
311  mon->zmcStatus = strList[x * 7 + 4];
312  mon->zmaStatus = strList[x * 7 + 5];
313  mon->events = strList[x * 7 + 6].toInt();
314  mon->function = strList[x * 7 + 7];
315  mon->enabled = (strList[x * 7 + 8].toInt() != 0);
316  }
317  }
318 }
319 
320 static QString stateToString(State state)
321 {
322  QString result = "UNKNOWN";
323 
324  switch (state)
325  {
326  case IDLE:
327  result = "IDLE";
328  break;
329  case PREALARM:
330  result = "PREALARM";
331  break;
332  case ALARM:
333  result = "ALARM";
334  break;
335  case ALERT:
336  result = "ALERT";
337  break;
338  case TAPE:
339  result = "TAPE";
340  break;
341  default:
342  result = "UNKNOWN";
343  }
344 
345  return result;
346 }
347 
349 {
350  QMutexLocker clocker(&m_commandLock);
351 
352  QStringList strList("GET_ALARM_STATES");
353  if (!sendReceiveStringList(strList))
354  return false;
355 
356  // sanity check
357  if (strList.size() < 2)
358  {
359  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
360  return false;
361  }
362 
363  bool bOK = false;
364  int monitorCount = strList[1].toInt(&bOK);
365  if (!bOK)
366  {
367  LOG(VB_GENERAL, LOG_ERR,
368  "ZMClient received bad int in getAlarmStates()");
369  return false;
370  }
371 
372  QMutexLocker locker(&m_listLock);
373 
374  bool changed = false;
375  for (int x = 0; x < monitorCount; x++)
376  {
377  int monID = strList[x * 2 + 2].toInt();
378  auto state = (State)strList[x * 2 + 3].toInt();
379 
380  if (m_monitorMap.contains(monID))
381  {
382  Monitor *mon = m_monitorMap.find(monID).value();
383  if (mon->state != state)
384  {
385  // alarm state has changed for this monitor
386  LOG(VB_GENERAL, LOG_DEBUG,
387  QString("ZMClient monitor %1 changed state from %2 to %3")
388  .arg(mon->name, stateToString(mon->state), stateToString(state)));
389  mon->previousState = mon->state;
390  mon->state = state;
391  changed = true;
392  }
393  }
394  }
395 
396  return changed;
397 }
398 
399 void ZMClient::getEventList(const QString &monitorName, bool oldestFirst,
400  const QString &date, bool includeContinuous,
401  std::vector<Event*> *eventList)
402 {
403  QMutexLocker locker(&m_commandLock);
404 
405  eventList->clear();
406 
407  QStringList strList("GET_EVENT_LIST");
408  strList << monitorName << (oldestFirst ? "1" : "0") ;
409  strList << date;
410  strList << (includeContinuous ? "1" : "0") ;
411 
412  if (!sendReceiveStringList(strList))
413  return;
414 
415  // sanity check
416  if (strList.size() < 2)
417  {
418  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
419  return;
420  }
421 
422  bool bOK = false;
423  int eventCount = strList[1].toInt(&bOK);
424  if (!bOK)
425  {
426  LOG(VB_GENERAL, LOG_ERR, "ZMClient received bad int in getEventList()");
427  return;
428  }
429 
430  // sanity check
431  if ((strList.size() - 2) / 6 != eventCount)
432  {
433  LOG(VB_GENERAL, LOG_ERR,
434  "ZMClient got a mismatch between the number of events and "
435  "the expected number of stringlist items in getEventList()");
436  return;
437  }
438 
439  QStringList::Iterator it = strList.begin();
440  it++; it++;
441  for (int x = 0; x < eventCount; x++)
442  {
443  eventList->push_back(
444  new Event(
445  (*it++).toInt(), /* eventID */
446  *it++, /* eventName */
447  (*it++).toInt(), /* monitorID */
448  *it++, /* monitorName */
449  QDateTime::fromString(*it++, Qt::ISODate), /* startTime */
450  *it++ /* length */));
451  }
452 }
453 
454 void ZMClient::getEventDates(const QString &monitorName, bool oldestFirst,
455  QStringList &dateList)
456 {
457  QMutexLocker locker(&m_commandLock);
458 
459  dateList.clear();
460 
461  QStringList strList("GET_EVENT_DATES");
462  strList << monitorName << (oldestFirst ? "1" : "0") ;
463 
464  if (!sendReceiveStringList(strList))
465  return;
466 
467  // sanity check
468  if (strList.size() < 2)
469  {
470  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
471  return;
472  }
473 
474  bool bOK = false;
475  int dateCount = strList[1].toInt(&bOK);
476  if (!bOK)
477  {
478  LOG(VB_GENERAL, LOG_ERR,
479  "ZMClient received bad int in getEventDates()");
480  return;
481  }
482 
483  // sanity check
484  if ((strList.size() - 3) != dateCount)
485  {
486  LOG(VB_GENERAL, LOG_ERR,
487  "ZMClient got a mismatch between the number of dates and "
488  "the expected number of stringlist items in getEventDates()");
489  return;
490  }
491 
492  QStringList::Iterator it = strList.begin();
493  it++; it++;
494  for (int x = 0; x < dateCount; x++)
495  {
496  dateList.append(*it++);
497  }
498 }
499 
500 void ZMClient::getFrameList(int eventID, std::vector<Frame*> *frameList)
501 {
502  QMutexLocker locker(&m_commandLock);
503 
504  frameList->clear();
505 
506  QStringList strList("GET_FRAME_LIST");
507  strList << QString::number(eventID);
508  if (!sendReceiveStringList(strList))
509  return;
510 
511  // sanity check
512  if (strList.size() < 2)
513  {
514  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
515  return;
516  }
517 
518  bool bOK = false;
519  int frameCount = strList[1].toInt(&bOK);
520  if (!bOK)
521  {
522  LOG(VB_GENERAL, LOG_ERR, "ZMClient received bad int in getFrameList()");
523  return;
524  }
525 
526  // sanity check
527  if ((strList.size() - 2) / 2 != frameCount)
528  {
529  LOG(VB_GENERAL, LOG_ERR,
530  "ZMClient got a mismatch between the number of frames and "
531  "the expected number of stringlist items in getFrameList()");
532  return;
533  }
534 
535  QStringList::Iterator it = strList.begin();
536  it++; it++;
537  for (int x = 0; x < frameCount; x++)
538  {
539  auto *item = new Frame;
540  item->type = *it++;
541  item->delta = (*it++).toDouble();
542  frameList->push_back(item);
543  }
544 }
545 
546 void ZMClient::deleteEvent(int eventID)
547 {
548  QMutexLocker locker(&m_commandLock);
549 
550  QStringList strList("DELETE_EVENT");
551  strList << QString::number(eventID);
552  sendReceiveStringList(strList);
553 }
554 
555 void ZMClient::deleteEventList(std::vector<Event*> *eventList)
556 {
557  QMutexLocker locker(&m_commandLock);
558 
559  // delete events in 100 event chunks
560  QStringList strList("DELETE_EVENT_LIST");
561  int count = 0;
562  std::vector<Event*>::iterator it;
563  for (it = eventList->begin(); it != eventList->end(); ++it)
564  {
565  strList << QString::number((*it)->eventID());
566 
567  if (++count == 100)
568  {
569  sendReceiveStringList(strList);
570  strList = QStringList("DELETE_EVENT_LIST");
571  count = 0;
572  }
573  }
574 
575  // make sure the last chunk is deleted
576  sendReceiveStringList(strList);
577 
578  // run zmaudit to clean up the orphaned db entries
579  strList = QStringList("RUN_ZMAUDIT");
580  sendReceiveStringList(strList);
581 }
582 
583 bool ZMClient::readData(unsigned char *data, int dataSize)
584 {
585  qint64 read = 0;
586  std::chrono::milliseconds errmsgtime { 0ms };
587  MythTimer timer;
588  timer.start();
589 
590  while (dataSize > 0)
591  {
592  qint64 sret = m_socket->Read((char*) data + read, dataSize, 100ms);
593  if (sret > 0)
594  {
595  read += sret;
596  dataSize -= sret;
597  if (dataSize > 0)
598  {
599  timer.start();
600  }
601  }
602  else if (sret < 0)
603  {
604  LOG(VB_GENERAL, LOG_ERR, "readData: Error, readBlock");
606  return false;
607  }
608  else if (!m_socket->IsConnected())
609  {
610  LOG(VB_GENERAL, LOG_ERR,
611  "readData: Error, socket went unconnected");
613  return false;
614  }
615  else
616  {
617  std::chrono::milliseconds elapsed = timer.elapsed();
618  if (elapsed > 10s)
619  {
620  if ((elapsed - errmsgtime) > 10s)
621  {
622  errmsgtime = elapsed;
623  LOG(VB_GENERAL, LOG_ERR,
624  QString("m_socket->: Waiting for data: %1 %2")
625  .arg(read).arg(dataSize));
626  }
627  }
628 
629  if (elapsed > 100s)
630  {
631  LOG(VB_GENERAL, LOG_ERR, "Error, readData timeout (readBlock)");
632  return false;
633  }
634  }
635  }
636 
637  return true;
638 }
639 
640 void ZMClient::getEventFrame(Event *event, int frameNo, MythImage **image)
641 {
642  QMutexLocker locker(&m_commandLock);
643 
644  if (*image)
645  {
646  (*image)->DecrRef();
647  *image = nullptr;
648  }
649 
650  QStringList strList("GET_EVENT_FRAME");
651  strList << QString::number(event->monitorID());
652  strList << QString::number(event->eventID());
653  strList << QString::number(frameNo);
654  strList << event->startTime(Qt::LocalTime).toString("yy/MM/dd/hh/mm/ss");
655  if (!sendReceiveStringList(strList))
656  return;
657 
658  // sanity check
659  if (strList.size() < 2)
660  {
661  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
662  return;
663  }
664 
665  // get frame length from data
666  int imageSize = strList[1].toInt();
667 
668  // grab the image data
669  auto *data = new unsigned char[imageSize];
670  if (!readData(data, imageSize))
671  {
672  LOG(VB_GENERAL, LOG_ERR,
673  "ZMClient::getEventFrame(): Failed to get image data");
674  delete [] data;
675  return;
676  }
677 
678  // get a MythImage
680 
681  // extract the image data and create a MythImage from it
682  if (!(*image)->loadFromData(data, imageSize, "JPEG"))
683  {
684  LOG(VB_GENERAL, LOG_ERR,
685  "ZMClient::getEventFrame(): Failed to load image from data");
686  }
687 
688  delete [] data;
689 }
690 
691 void ZMClient::getAnalyseFrame(Event *event, int frameNo, QImage &image)
692 {
693  QMutexLocker locker(&m_commandLock);
694 
695  QStringList strList("GET_ANALYSE_FRAME");
696  strList << QString::number(event->monitorID());
697  strList << QString::number(event->eventID());
698  strList << QString::number(frameNo);
699  strList << event->startTime(Qt::LocalTime).toString("yy/MM/dd/hh/mm/ss");
700  if (!sendReceiveStringList(strList))
701  {
702  image = QImage();
703  return;
704  }
705 
706  // sanity check
707  if (strList.size() < 2)
708  {
709  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
710  return;
711  }
712 
713  // get frame length from data
714  int imageSize = strList[1].toInt();
715 
716  // grab the image data
717  auto *data = new unsigned char[imageSize];
718  if (!readData(data, imageSize))
719  {
720  LOG(VB_GENERAL, LOG_ERR,
721  "ZMClient::getAnalyseFrame(): Failed to get image data");
722  image = QImage();
723  }
724  else
725  {
726  // extract the image data and create a QImage from it
727  if (!image.loadFromData(data, imageSize, "JPEG"))
728  {
729  LOG(VB_GENERAL, LOG_ERR,
730  "ZMClient::getAnalyseFrame(): Failed to load image from data");
731  image = QImage();
732  }
733  }
734 
735  delete [] data;
736 }
737 
738 int ZMClient::getLiveFrame(int monitorID, QString &status, FrameData& buffer)
739 {
740  QMutexLocker locker(&m_commandLock);
741 
742  QStringList strList("GET_LIVE_FRAME");
743  strList << QString::number(monitorID);
744  if (!sendReceiveStringList(strList))
745  {
746  if (strList.empty())
747  {
748  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
749  return 0;
750  }
751 
752  // the server sends a "WARNING" message if there is no new
753  // frame available we can safely ignore it
754  if (strList[0].startsWith("WARNING"))
755  {
756  return 0;
757  }
758  status = strList[0];
759  return 0;
760  }
761 
762  // sanity check
763  if (strList.size() < 4)
764  {
765  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
766  return 0;
767  }
768 
769  // get status
770  status = strList[2];
771 
772  // get frame length from data
773  size_t imageSize = strList[3].toInt();
774 
775  if (buffer.size() < imageSize)
776  {
777  LOG(VB_GENERAL, LOG_ERR,
778  "ZMClient::getLiveFrame(): Live frame buffer is too small!");
779  return 0;
780  }
781 
782  // read the frame data
783  if (imageSize == 0)
784  return 0;
785 
786  if (!readData(buffer.data(), imageSize))
787  {
788  LOG(VB_GENERAL, LOG_ERR,
789  "ZMClient::getLiveFrame(): Failed to get image data");
790  return 0;
791  }
792 
793  return imageSize;
794 }
795 
796 void ZMClient::getCameraList(QStringList &cameraList)
797 {
798  QMutexLocker locker(&m_commandLock);
799 
800  cameraList.clear();
801 
802  QStringList strList("GET_CAMERA_LIST");
803  if (!sendReceiveStringList(strList))
804  return;
805 
806  // sanity check
807  if (strList.size() < 2)
808  {
809  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
810  return;
811  }
812 
813  bool bOK = false;
814  int cameraCount = strList[1].toInt(&bOK);
815  if (!bOK)
816  {
817  LOG(VB_GENERAL, LOG_ERR,
818  "ZMClient received bad int in getCameraList()");
819  return;
820  }
821 
822  // sanity check
823  if (strList.size() < cameraCount + 2)
824  {
825  LOG(VB_GENERAL, LOG_ERR, QString(
826  "ZMClient got a mismatch between the number of cameras (%1) and "
827  "the expected number of stringlist items (%2) in getCameraList()")
828  .arg(cameraCount).arg(strList.size()));
829  return;
830  }
831 
832  for (int x = 0; x < cameraCount; x++)
833  {
834  cameraList.append(strList[x + 2]);
835  }
836 }
837 
839 {
840  QMutexLocker locker(&m_listLock);
841  return m_monitorList.count();
842 }
843 
845 {
846  QMutexLocker locker(&m_listLock);
847 
848  if (pos < 0 || pos > m_monitorList.count() - 1)
849  return nullptr;
850 
851  return m_monitorList.at(pos);
852 }
853 
855 {
856  QMutexLocker locker(&m_listLock);
857 
858  if (m_monitorMap.contains(monID))
859  return m_monitorMap.find(monID).value();
860 
861  return nullptr;
862 }
863 
865 {
866  QMutexLocker clocker(&m_commandLock);
867  QMutexLocker locker(&m_listLock);
868 
869  for (int x = 0; x < m_monitorList.count(); x++)
870  delete m_monitorList.at(x);
871 
872  m_monitorList.clear();
873  m_monitorMap.clear();
874 
875  QStringList strList("GET_MONITOR_LIST");
876  if (!sendReceiveStringList(strList))
877  return;
878 
879  // sanity check
880  if (strList.size() < 2)
881  {
882  LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
883  return;
884  }
885 
886  bool bOK = false;
887  int monitorCount = strList[1].toInt(&bOK);
888  if (!bOK)
889  {
890  LOG(VB_GENERAL, LOG_ERR,
891  "ZMClient received bad int in getMonitorList()");
892  return;
893  }
894 
895  // sanity check
896  if ((strList.size() - 2) / 5 != monitorCount)
897  {
898  LOG(VB_GENERAL, LOG_ERR,
899  "ZMClient got a mismatch between the number of monitors and "
900  "the expected number of stringlist items in getMonitorList()");
901  return;
902  }
903 
904  // get list of monitor id's that need monitoring
905  QString s = gCoreContext->GetSetting("ZoneMinderNotificationMonitors");
906  QStringList notificationMonitors = s.split(",");
907 
908  for (int x = 0; x < monitorCount; x++)
909  {
910  auto *item = new Monitor;
911  item->id = strList[x * 5 + 2].toInt();
912  item->name = strList[x * 5 + 3];
913  item->width = strList[x * 5 + 4].toInt();
914  item->height = strList[x * 5 + 5].toInt();
915  item->bytes_per_pixel = strList[x * 5 + 6].toInt();
916  item->zmcStatus = "";
917  item->zmaStatus = "";
918  item->events = 0;
919  item->status = "";
920  item->showNotifications = notificationMonitors.contains(QString::number(item->id));
921 
922  m_monitorList.append(item);
923  m_monitorMap.insert(item->id, item);
924 
925  LOG(VB_GENERAL, LOG_NOTICE,
926  QString("Monitor: %1 (%2) is using %3 bytes per pixel")
927  .arg(item->name).arg(item->id).arg(item->bytes_per_pixel));
928  }
929 }
930 
931 void ZMClient::setMonitorFunction(const int monitorID, const QString &function, const bool enabled)
932 {
933  QMutexLocker locker(&m_commandLock);
934 
935  QStringList strList("SET_MONITOR_FUNCTION");
936  strList << QString::number(monitorID);
937  strList << function;
938  strList << QString::number(static_cast<int>(enabled));
939 
940  if (!sendReceiveStringList(strList))
941  return;
942 }
943 
945 {
946  QString s;
947 
948  for (int x = 0; x < m_monitorList.count(); x++)
949  {
950  Monitor *mon = m_monitorList.at(x);
951  if (mon->showNotifications)
952  {
953  if (!s.isEmpty())
954  s += QString(",%1").arg(mon->id);
955  else
956  s = QString("%1").arg(mon->id);
957  }
958  }
959 
960  gCoreContext->SaveSetting("ZoneMinderNotificationMonitors", s);
961 }
962 
963 void ZMClient::customEvent (QEvent* event)
964 {
965  if (event->type() == MythEvent::MythEventMessage)
966  {
967  auto *me = dynamic_cast<MythEvent*>(event);
968  if (!me)
969  return;
970 
971  if (me->Message().startsWith("ZONEMINDER_NOTIFICATION"))
972  {
973  QStringList list = me->Message().simplified().split(' ');
974 
975  if (list.size() < 2)
976  return;
977 
978  int monID = list[1].toInt();
979  showMiniPlayer(monID);
980  }
981  }
982 
983  QObject::customEvent(event);
984 }
985 
986 void ZMClient::showMiniPlayer(int monitorID) const
987 {
988  if (!isMiniPlayerEnabled())
989  return;
990 
991  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
992 
993  auto *miniPlayer = new ZMMiniPlayer(popupStack);
994 
995  miniPlayer->setAlarmMonitor(monitorID);
996 
997  if (miniPlayer->Create())
998  popupStack->AddScreen(miniPlayer);
999 }
MythTimer::elapsed
std::chrono::milliseconds elapsed(void)
Returns milliseconds elapsed since last start() or restart()
Definition: mythtimer.cpp:91
MythEvent::MythEventMessage
static Type MythEventMessage
Definition: mythevent.h:78
hardwareprofile.smolt.timeout
float timeout
Definition: smolt.py:103
ZMClient::m_monitorList
QList< Monitor * > m_monitorList
Definition: zmclient.h:86
Monitor::function
QString function
Definition: zmdefines.h:109
ReferenceCounter::DecrRef
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
Definition: referencecounter.cpp:125
ShowNotificationError
void ShowNotificationError(const QString &msg, const QString &from, const QString &detail, const VNMask visibility, const MythNotification::Priority priority)
convenience utility to display error message as notification
Definition: mythnotificationcenter.cpp:1428
IDLE
@ IDLE
Definition: zmserver.h:70
ZMClient::m_socket
MythSocket * m_socket
Definition: zmclient.h:89
ZMClient::m_socketLock
QRecursiveMutex m_socketLock
Definition: zmclient.h:93
MythTimer
A QElapsedTimer based timer to replace use of QTime as a timer.
Definition: mythtimer.h:13
Monitor::name
QString name
Definition: zmdefines.h:107
ZMClient::getServerStatus
void getServerStatus(QString &status, QString &cpuStat, QString &diskStat)
Definition: zmclient.cpp:257
ZMClient::getMonitorCount
int getMonitorCount(void)
Definition: zmclient.cpp:838
discid.disc.read
def read(device=None, features=[])
Definition: disc.py:35
Monitor::events
int events
Definition: zmdefines.h:114
MythPainter::GetFormatImage
MythImage * GetFormatImage()
Returns a blank reference counted image in the format required for the Draw functions for this painte...
Definition: mythpainter.cpp:540
Frame
Definition: zmdefines.h:93
ZMClient::ZMClient
ZMClient()
Definition: zmclient.cpp:26
TAPE
@ TAPE
Definition: zmserver.h:74
ZMClient::deleteEventList
void deleteEventList(std::vector< Event * > *eventList)
Definition: zmclient.cpp:555
MythEvent
This class is used as a container for messages.
Definition: mythevent.h:16
ZMClient::m_hostname
QString m_hostname
Definition: zmclient.h:95
mythdialogbox.h
MythScreenStack
Definition: mythscreenstack.h:16
ZMClient::setupZMClient
static bool setupZMClient(void)
Definition: zmclient.cpp:45
Monitor::previousState
State previousState
Definition: zmdefines.h:123
PREALARM
@ PREALARM
Definition: zmserver.h:71
MythSocket::DisconnectFromHost
void DisconnectFromHost(void)
Definition: mythsocket.cpp:511
MythTimer::start
void start(void)
starts measuring elapsed time.
Definition: mythtimer.cpp:47
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
ZMClient::getMonitorByID
Monitor * getMonitorByID(int monID)
Definition: zmclient.cpp:854
ZMClient::isMiniPlayerEnabled
bool isMiniPlayerEnabled(void) const
Definition: zmclient.h:65
Monitor::zmcStatus
QString zmcStatus
Definition: zmdefines.h:112
ZMMiniPlayer
Definition: zmminiplayer.h:10
MythMainWindow::GetPainter
MythPainter * GetPainter()
Definition: mythmainwindow.cpp:257
MythSocket::ConnectToHost
bool ConnectToHost(const QString &hostname, quint16 port)
connect to host
Definition: mythsocket.cpp:387
MythEvent::Message
const QString & Message() const
Definition: mythevent.h:65
MythSocket::IsConnected
bool IsConnected(void) const
Definition: mythsocket.cpp:564
ZMClient::m_zmclientReady
bool m_zmclientReady
Definition: zmclient.h:99
Monitor::enabled
bool enabled
Definition: zmdefines.h:110
ZMClient::saveNotificationMonitors
void saveNotificationMonitors(void)
Definition: zmclient.cpp:944
MythObservable::addListener
void addListener(QObject *listener)
Add a listener to the observable.
Definition: mythobservable.cpp:38
MythSocket
Class for communcating between myth backends and frontends.
Definition: mythsocket.h:26
zmclient.h
ZMClient::m_retryTimer
QTimer * m_retryTimer
Definition: zmclient.h:98
mythdate.h
mythlogging.h
Event
Event details.
Definition: zmdefines.h:26
ZMClient::getEventDates
void getEventDates(const QString &monitorName, bool oldestFirst, QStringList &dateList)
Definition: zmclient.cpp:454
ZMClient::restartConnection
void restartConnection(void)
Definition: zmclient.cpp:220
stateToString
static QString stateToString(State state)
Definition: zmclient.cpp:320
State
State
Definition: zmserver.h:68
ZMClient::m_bConnected
bool m_bConnected
Definition: zmclient.h:97
Monitor::showNotifications
bool showNotifications
Definition: zmdefines.h:121
ZMClient::connectToHost
bool connectToHost(const QString &hostname, unsigned int port)
Definition: zmclient.cpp:62
ZMClient::getAnalyseFrame
void getAnalyseFrame(Event *event, int frameNo, QImage &image)
Definition: zmclient.cpp:691
ALERT
@ ALERT
Definition: zmserver.h:73
ZMClient::updateAlarmStates
bool updateAlarmStates(void)
Definition: zmclient.cpp:348
ZM_PROTOCOL_VERSION
#define ZM_PROTOCOL_VERSION
Definition: zmclient.cpp:22
ZMClient::getEventList
void getEventList(const QString &monitorName, bool oldestFirst, const QString &date, bool includeContinuous, std::vector< Event * > *eventList)
Definition: zmclient.cpp:399
ZMClient::get
static ZMClient * get(void)
Definition: zmclient.cpp:38
ZMClient::doGetMonitorList
void doGetMonitorList(void)
Definition: zmclient.cpp:864
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:60
ZMClient::sendReceiveStringList
bool sendReceiveStringList(QStringList &strList)
Definition: zmclient.cpp:124
MythSocket::Read
int Read(char *data, int size, std::chrono::milliseconds max_wait)
Definition: mythsocket.cpp:540
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:936
zmminiplayer.h
Monitor::zmaStatus
QString zmaStatus
Definition: zmdefines.h:113
MythDate::fromString
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:30
ZMClient::getFrameList
void getFrameList(int eventID, std::vector< Frame * > *frameList)
Definition: zmclient.cpp:500
ZMClient::m_listLock
QRecursiveMutex m_listLock
Definition: zmclient.h:83
Monitor::state
State state
Definition: zmdefines.h:122
Frame::type
QString type
Definition: zmdefines.h:95
ZMClient::updateMonitorStatus
void updateMonitorStatus(void)
Definition: zmclient.cpp:277
ZMClient::shutdown
void shutdown()
Definition: zmclient.cpp:230
ZMClient::m_commandLock
QRecursiveMutex m_commandLock
Definition: zmclient.h:84
ZMClient::m_zmclient
static ZMClient * m_zmclient
Definition: zmclient.h:24
MythImage
Definition: mythimage.h:36
Event::eventID
int eventID(void) const
Definition: zmdefines.h:48
MythDate::ISODate
@ ISODate
Default UTC.
Definition: mythdate.h:17
ZMClient::getCameraList
void getCameraList(QStringList &cameraList)
Definition: zmclient.cpp:796
ZMClient::deleteEvent
void deleteEvent(int eventID)
Definition: zmclient.cpp:546
ZMClient::readData
bool readData(unsigned char *data, int dataSize)
Definition: zmclient.cpp:583
ZMClient::m_monitorMap
QMap< int, Monitor * > m_monitorMap
Definition: zmclient.h:87
ZMClient::showMiniPlayer
void showMiniPlayer(int monitorID) const
Definition: zmclient.cpp:986
GetNotificationCenter
MythNotificationCenter * GetNotificationCenter(void)
Definition: mythmainwindow.cpp:124
mythcontext.h
ALARM
@ ALARM
Definition: zmserver.h:72
Event::monitorID
int monitorID(void) const
Definition: zmdefines.h:46
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:104
ZMClient::customEvent
void customEvent(QEvent *event) override
Definition: zmclient.cpp:963
ZMClient::~ZMClient
~ZMClient() override
Definition: zmclient.cpp:241
MythMainWindow::GetStack
MythScreenStack * GetStack(const QString &Stackname)
Definition: mythmainwindow.cpp:322
Monitor::id
int id
Definition: zmdefines.h:106
FrameData
std::array< uint8_t, MAX_IMAGE_SIZE > FrameData
Definition: zmserver.h:33
Monitor
Definition: zmdefines.h:99
ZMClient::getLiveFrame
int getLiveFrame(int monitorID, QString &status, FrameData &buffer)
Definition: zmclient.cpp:738
MythCoreContext::SaveSetting
void SaveSetting(const QString &key, int newValue)
Definition: mythcorecontext.cpp:905
ZMClient::getMonitorAt
Monitor * getMonitorAt(int pos)
Definition: zmclient.cpp:844
ZMClient::setMonitorFunction
void setMonitorFunction(int monitorID, const QString &function, bool enabled)
Definition: zmclient.cpp:931
mythmainwindow.h
MythScreenStack::AddScreen
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Definition: mythscreenstack.cpp:50
ShowOkPopup
MythConfirmationDialog * ShowOkPopup(const QString &message, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
Definition: mythdialogbox.cpp:558
MythObservable::removeListener
void removeListener(QObject *listener)
Remove a listener to the observable.
Definition: mythobservable.cpp:55
ZMClient::m_port
uint m_port
Definition: zmclient.h:96
ZMClient::checkProtoVersion
bool checkProtoVersion(void)
Definition: zmclient.cpp:180
MythSocket::SendReceiveStringList
bool SendReceiveStringList(QStringList &list, uint min_reply_length=0, std::chrono::milliseconds timeoutMS=kLongTimeout)
Definition: mythsocket.cpp:339
ZMClient
Definition: zmclient.h:17
ZMClient::getEventFrame
void getEventFrame(Event *event, int frameNo, MythImage **image)
Definition: zmclient.cpp:640
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:922