Broad question, but I am undertaking some alarm rationalization work and am wondering if there is an efficient way to query what the value of all alarm severity fields are across all relevant object classes in a ClearSCADA database?
The only way I know of currently is to individually query object classes like CeNetAnalog, CPointAlg, etc. one by one for all of their alarm severity fields and manually compile all the information somewhere like a spreadsheet. Quite a time-consuming process and my main concern is that it is very easy to accidentally miss alarms on object types that I'm not aware even had configurable alarms in the first place. For example, I only just learnt that CRootGroup has a WSEventSeverity field for workstation events as well as multiple aggregates that each have severity settings too.
I'm just thinking could there be a way to work backwards instead and somehow start from the severity settings in Server Config and somehow grab a list of all references to that?
Solved! Go to Solution.
Maybe not the most efficient way, but the way I did something like this was:
Make a mimic with separate list of Modbus Digitals, Modbus Analogs, OPC Digitals, OPC Analogs, Internal Digitals, Internal Analogs, etc, each with all of the alarm fields to the point that I was happy that I had everything I wanted.
Then I copied the Query from each list in to its own SQL Export object and gave each export a unique Output file name. Now whenever someone asks me for the alarm details, all I need to do is execute each SQL Export and copy the files from the server to an email.
No simple way, typically I do what you propose and query each table and union them all together. I once tried to write a program to find all fields call "Severity" and auto generate some SQL but I don't think I ever finished it.
The way the ClearSCADA database is structured does make some thing much easier... however in cases such as this it can be unhelpful.
It almost needs a feature request for a summary table of 'Alarm Severity '.. not that this would help in many situations.
Alarm redirections can often make the actual object configured severity meaningless.
Thanks for confirming Adam. At least it sounds like I'm on the right track with how I'm approaching this and not missing something obvious. Some sort of Alarm Severity Summary table as Bevan suggested would be very helpful, although I'm not exactly sure how feasible it is to implement such a feature.
There's a variable number of severities per object. Here is a 'meta query' you can use to find severity data:
SELECT 'select ''' || TABLE || ''',''' || NAME || ''',T.Id, T.FullName, T.' || NAME || ',S.Description from ' || TABLE || ' T left join CSeverity S on T.' || NAME || ' = S.Priority ' AS SQL FROM DBFIELDDEF WHERE NAME LIKE '%Severity' AND SIZE = 1 AND TYPE = 1
The output is a longish list of queries for each database type.
This sounds like a really nice opportunity to ask for a feature request to do something like SQL Views but within the CS database. Additionally, server-side cached query objects would be really nice as well.
Constantly having to union together OPC stuff isn't a big deal but gets repetitive to type out.
For cached queries, have a query object (like the ones for GIS) that runs the query every x seconds/minutes and caches the result set. Users can query those objects like they would a view and get the results directly from cache rather than having the server re-query it. This could alleviate a big load when you have a server that runs a large number of clients. Having something in there properties where it logs access count from client vs scheduled and stops running if the access count from clients doesn't increase after x minutes would also alleviate unnecessary runs.
I've been trying to find ways to utilize the query objects for GIS stuff in a way that was not intended and I've yet to find a use outside of just storing common queries on them.
Thanks Steve, I got around to trying your meta-query and it helped considerably. It needed a little bit of tweaking, mainly around all the aggregate classes as they need their select statements manually modified to inner join on CDBObject (as they don't directly contain a FullName).