BOSWatch 3
Python Script to receive and decode German BOS Information with rtl_fm and multimon-NG
 
Loading...
Searching...
No Matches
plugin.mysql.BoswatchPlugin Class Reference

Description of the Plugin. More...

Public Member Functions

 __init__ (self, config)
 Do not change anything here!
 
 onLoad (self)
 Called by import of the plugin.
 
 setup (self)
 Called before alarm.
 
 fms (self, bwPacket)
 Called on FMS alarm.
 
 pocsag (self, bwPacket)
 Called on POCSAG alarm.
 
 zvei (self, bwPacket)
 Called on ZVEI alarm.
 
 msg (self, bwPacket)
 Called on MSG packet.
 
 teardown (self)
 Called after alarm.
 
 onUnload (self)
 Called by destruction of the plugin.
 
- Public Member Functions inherited from plugin.pluginBase.PluginBase
 parseWildcards (self, msg)
 Return the message with parsed wildcards.
 

Data Fields

 sqlInserts
 
 connection
 
 cursor
 
- Data Fields inherited from plugin.pluginBase.PluginBase
 config
 

Protected Member Functions

 _connect (self)
 
- Protected Member Functions inherited from plugin.pluginBase.PluginBase
 _cleanup (self)
 Cleanup routine calls onUnload() directly.
 
 _run (self, bwPacket)
 start an complete running turn of an plugin.
 
 _getStatistics (self)
 Returns statistical information's from last plugin run.
 

Additional Inherited Members

- Protected Attributes inherited from plugin.pluginBase.PluginBase
 _pluginName
 
 _bwPacket
 
 _sumTime
 
 _cumTime
 
 _setupTime
 
 _alarmTime
 
 _teardownTime
 
 _runCount
 
 _setupErrorCount
 
 _alarmErrorCount
 
 _teardownErrorCount
 
- Static Protected Attributes inherited from plugin.pluginBase.PluginBase
list _pluginsActive = []
 

Detailed Description

Description of the Plugin.

Constructor & Destructor Documentation

◆ __init__()

plugin.mysql.BoswatchPlugin.__init__ (   self,
  config 
)

Do not change anything here!

Reimplemented from plugin.pluginBase.PluginBase.

33 def __init__(self, config):
34 r"""!Do not change anything here!"""
35 super().__init__(__name__, config) # you can access the config class on 'self.config'
36

Member Function Documentation

◆ onLoad()

plugin.mysql.BoswatchPlugin.onLoad (   self)

Called by import of the plugin.

Reimplemented from plugin.pluginBase.PluginBase.

37 def onLoad(self):
38 r"""!Called by import of the plugin"""
39 self.sqlInserts = {
40 "pocsag": "INSERT INTO boswatch (packetTimestamp, packetMode, pocsag_ric, pocsag_subric, pocsag_subricText, pocsag_message, pocsag_bitrate, serverName, serverVersion, serverBuildDate, serverBranch, clientName, clientIP, clientVersion, clientBuildDate, clientBranch, inputSource, frequency) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)",
41 "zvei": "INSERT INTO boswatch (packetTimestamp, packetMode, zvei_tone, serverName, serverVersion, serverBuildDate, serverBranch, clientName, clientIP, clientVersion, clientBuildDate, clientBranch, inputSource, frequency) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)",
42 "fms": "INSERT INTO boswatch (packetTimestamp, packetMode, fms_fms, fms_service, fms_country, fms_location, fms_vehicle, fms_status, fms_direction, fms_directionText, fms_tacticalInfo, serverName, serverVersion, serverBuildDate, serverBranch, clientName, clientIP, clientVersion, clientBuildDate, clientBranch, inputSource, frequency) VALUE (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)",
43 "msg": "INSERT INTO boswatch (packetTimestamp, packetMode, serverName, serverVersion, serverBuildDate, serverBranch, clientName, clientIP, clientVersion, clientBuildDate, clientBranch, inputSource, frequency) VALUE (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"
44 }
45
46 self.connection = None
47 self.cursor = None
48 self._connect() # trying to establish connection, no crash if fail
49

◆ setup()

plugin.mysql.BoswatchPlugin.setup (   self)

Called before alarm.

Reimplemented from plugin.pluginBase.PluginBase.

50 def setup(self):
51 r"""!Called before alarm"""
52 # Zero the cursor at the start of each alarm
53 self.cursor = None
54
55 if self.connection is None:
56 if not self._connect():
57 logging.error("MySQL still unavailable – skipping alarm")
58 return
59 else:
60 try:
61 self.connection.ping(reconnect=True, attempts=3, delay=2)
62 except mysql.connector.Error:
63 logging.warning("Ping failed, trying full reconnect...")
64 if not self._connect():
65 return
66
67 # Only when the connection is established do we create a fresh cursor for this alarm
68 if self.connection:
69 try:
70 self.cursor = self.connection.cursor()
71 except mysql.connector.Error:
72 self.cursor = None
73

◆ fms()

plugin.mysql.BoswatchPlugin.fms (   self,
  bwPacket 
)

Called on FMS alarm.

Parameters
bwPacketbwPacket instance

Reimplemented from plugin.pluginBase.PluginBase.

74 def fms(self, bwPacket):
75 r"""!Called on FMS alarm
76
77 @param bwPacket: bwPacket instance"""
78 if self.cursor is None:
79 logging.warning("MySQL unavailable, fms packet dropped")
80 return
81
82 val = (
83 datetime.fromtimestamp(float(bwPacket.get("timestamp"))),
84 bwPacket.get("mode"),
85 bwPacket.get("fms"),
86 bwPacket.get("service"),
87 bwPacket.get("country"),
88 bwPacket.get("location"),
89 bwPacket.get("vehicle"),
90 bwPacket.get("status"),
91 bwPacket.get("direction"),
92 bwPacket.get("directionText"),
93 bwPacket.get("tacticalInfo"),
94 bwPacket.get("serverName"),
95 bwPacket.get("serverVersion"),
96 bwPacket.get("serverBuildDate"),
97 bwPacket.get("serverBranch"),
98 bwPacket.get("clientName"),
99 bwPacket.get("clientIP"),
100 bwPacket.get("clientVersion"),
101 bwPacket.get("clientBuildDate"),
102 bwPacket.get("clientBranch"),
103 bwPacket.get("inputSource"),
104 bwPacket.get("frequency")
105 )
106 self.cursor.execute(self.sqlInserts.get("fms"), val)
107

◆ pocsag()

plugin.mysql.BoswatchPlugin.pocsag (   self,
  bwPacket 
)

Called on POCSAG alarm.

Parameters
bwPacketbwPacket instance

Reimplemented from plugin.pluginBase.PluginBase.

108 def pocsag(self, bwPacket):
109 r"""!Called on POCSAG alarm
110
111 @param bwPacket: bwPacket instance"""
112 if self.cursor is None:
113 logging.warning("MySQL unavailable, pocsag packet dropped")
114 return
115
116 val = (
117 datetime.fromtimestamp(float(bwPacket.get("timestamp"))),
118 bwPacket.get("mode"),
119 bwPacket.get("ric"),
120 bwPacket.get("subric"),
121 bwPacket.get("subricText"),
122 bwPacket.get("message"),
123 bwPacket.get("bitrate"),
124 bwPacket.get("serverName"),
125 bwPacket.get("serverVersion"),
126 bwPacket.get("serverBuildDate"),
127 bwPacket.get("serverBranch"),
128 bwPacket.get("clientName"),
129 bwPacket.get("clientIP"),
130 bwPacket.get("clientVersion"),
131 bwPacket.get("clientBuildDate"),
132 bwPacket.get("clientBranch"),
133 bwPacket.get("inputSource"),
134 bwPacket.get("frequency")
135 )
136 self.cursor.execute(self.sqlInserts.get("pocsag"), val)
137

◆ zvei()

plugin.mysql.BoswatchPlugin.zvei (   self,
  bwPacket 
)

Called on ZVEI alarm.

Parameters
bwPacketbwPacket instance

Reimplemented from plugin.pluginBase.PluginBase.

138 def zvei(self, bwPacket):
139 r"""!Called on ZVEI alarm
140
141 @param bwPacket: bwPacket instance"""
142 if self.cursor is None:
143 logging.warning("MySQL unavailable, zvei packet dropped")
144 return
145
146 val = (
147 datetime.fromtimestamp(float(bwPacket.get("timestamp"))),
148 bwPacket.get("mode"),
149 bwPacket.get("tone"),
150 bwPacket.get("serverName"),
151 bwPacket.get("serverVersion"),
152 bwPacket.get("serverBuildDate"),
153 bwPacket.get("serverBranch"),
154 bwPacket.get("clientName"),
155 bwPacket.get("clientIP"),
156 bwPacket.get("clientVersion"),
157 bwPacket.get("clientBuildDate"),
158 bwPacket.get("clientBranch"),
159 bwPacket.get("inputSource"),
160 bwPacket.get("frequency")
161 )
162 self.cursor.execute(self.sqlInserts.get("zvei"), val)
163

◆ msg()

plugin.mysql.BoswatchPlugin.msg (   self,
  bwPacket 
)

Called on MSG packet.

Parameters
bwPacketbwPacket instance

Reimplemented from plugin.pluginBase.PluginBase.

164 def msg(self, bwPacket):
165 r"""!Called on MSG packet
166
167 @param bwPacket: bwPacket instance"""
168 if self.cursor is None:
169 logging.warning("MySQL unavailable, msg packet dropped")
170 return
171
172 val = (
173 datetime.fromtimestamp(float(bwPacket.get("timestamp"))),
174 bwPacket.get("mode"),
175 bwPacket.get("serverName"),
176 bwPacket.get("serverVersion"),
177 bwPacket.get("serverBuildDate"),
178 bwPacket.get("serverBranch"),
179 bwPacket.get("clientName"),
180 bwPacket.get("clientIP"),
181 bwPacket.get("clientVersion"),
182 bwPacket.get("clientBuildDate"),
183 bwPacket.get("clientBranch"),
184 bwPacket.get("inputSource"),
185 bwPacket.get("frequency")
186 )
187 self.cursor.execute(self.sqlInserts.get("msg"), val)
188

◆ teardown()

plugin.mysql.BoswatchPlugin.teardown (   self)

Called after alarm.

Reimplemented from plugin.pluginBase.PluginBase.

189 def teardown(self):
190 r"""!Called after alarm"""
191 if self.connection and self.cursor:
192 try:
193 self.connection.commit()
194 self.cursor.close()
195 except mysql.connector.Error:
196 pass
197 finally:
198 # Ganz wichtig: Nach dem Schließen auf None setzen!
199 self.cursor = None
200

◆ onUnload()

plugin.mysql.BoswatchPlugin.onUnload (   self)

Called by destruction of the plugin.

Reimplemented from plugin.pluginBase.PluginBase.

201 def onUnload(self):
202 r"""!Called by destruction of the plugin"""
203 if self.connection:
204 self.connection.close()
205

◆ _connect()

plugin.mysql.BoswatchPlugin._connect (   self)
protected
Tries to establish MySQL connection. Returns True on success.
206 def _connect(self):
207 r"""Tries to establish MySQL connection. Returns True on success."""
208 try:
209 self.connection = mysql.connector.connect(
210 host=self.config.get("host"),
211 user=self.config.get("user"),
212 password=self.config.get("password"),
213 database=self.config.get("database"),
214 )
215 # IMPORTANT: Use a local variable for the initialization cursor
216 check_cursor = self.connection.cursor()
217 check_cursor.execute("SHOW TABLES LIKE 'boswatch'")
218
219 if check_cursor.fetchone() is None:
220 with open('init_db.sql') as f:
221 for stmnt in f.read().split(';'):
222 clean_stmnt = stmnt.strip()
223 if clean_stmnt:
224 check_cursor.execute(clean_stmnt)
225 self.connection.commit()
226
227 check_cursor.close()
228 # self.cursor intentionally remains None here!
229 logging.info("MySQL connection established.")
230 return True
231 except mysql.connector.Error as e:
232 logging.error("MySQL connection failed: %s – running without DB", e)
233 self.connection = None
234 self.cursor = None # To be on the safe side, zero it
235 return False

Field Documentation

◆ sqlInserts

plugin.mysql.BoswatchPlugin.sqlInserts

◆ connection

plugin.mysql.BoswatchPlugin.connection

◆ cursor

plugin.mysql.BoswatchPlugin.cursor