################################################################ ################################################################ ## Version: 1.0 / Author: Dillon Uzar ## ## DESC: For use in FMS in recording Flow Management data ## WARN: Modifying code may cause system to function incorrectly ################################################################ ################################################################ import json import system import time ####################################################### ####################################################### ####################################################### #### Constants ####################################################### # Logger: LOG = system.util.logger("FMS Handler") # For inserting data into database: INSERT_QUERY = "INSERT INTO fms_history (conveyor, segment, data) VALUES (?,?,?)" ####################################################### ####################################################### ####################################################### #### Parsing Utils ####################################################### def extractNibble(val, nibble): if val is not None: return (val >> (nibble*4)) & 0x0F def logTime(title, conv, seg, data, start_time): millisec = round((time.time() - start_time) * 1000, 1) LOG.info("%s[CONV=%s][SEG=%s][DATA=%s] took %sms to process" % (title, conv, seg, data, millisec)) ####################################################### ####################################################### ####################################################### #### Tag Event Handling ####################################################### def logSegment(conveyor, segment, data): # Log event in SQL: # Insert into FMS History: start_time = time.time() INSERT_QUERY = "INSERT INTO fms_history (conveyor, segment, data) VALUES (?,?,?)" system.db.runPrepUpdate(INSERT_QUERY, [conveyor, segment, data]) #logTime("FMS[DB_INSERT]", conveyor, segment, data, start_time) def dintOnChange(tag, tagPath, previousValue, currentValue, initialChange, missedEvents): # Don't execute on startup, or if new value is bad quality: if currentValue.quality.isGood(): # Only consider it a change if the value is different: if currentValue.value <> previousValue.value: id = int(tagPath.split("/")[-1].replace("DINT", "")) conveyor = tag['parameters']['LabelFull'] # ID=0 is unique where the first nibble is the average of all segments, the 7 other segments are normal segments: if id == 0: # Ignore first nibble, which is the average of all segments: for i in range(1, 8): # Check if segment changed: curVal = extractNibble(currentValue.value, i) prevVal = extractNibble(previousValue.value, i) if curVal <> prevVal: segment = i - 1 logSegment(conveyor, segment, curVal) else: for i in range(0, 8): # Check if segment changed: curVal = extractNibble(currentValue.value, i) prevVal = extractNibble(previousValue.value, i) if curVal <> prevVal: segment = i + (id-1)*8 + 7 logSegment(conveyor, segment, curVal) ####################################################### ####################################################### ####################################################### #### Graphics Tag Scripts ####################################################### """ radial-gradient(circle at 30%, #f5bff5 calc((var(--conv-width) - 4px)/2*0.25), #000 calc((var(--conv-width) - 4px)/2*0.25), #000 calc((var(--conv-width) - 4px)/2*0.25 + 1px), transparent calc((var(--conv-width) - 4px)/2*0.25 + 1px)), radial-gradient(circle at 50%, #d900d9 calc((var(--conv-width) - 4px)/2*1), #000 calc((var(--conv-width) - 4px)/2*1), #000 calc((var(--conv-width) - 4px)/2*1 + 1px), transparent calc((var(--conv-width) - 4px)/2*0.25 + 1px)), radial-gradient(circle at 70%, #ec7fec 7px, #000 7px, #000 8px, transparent 8px), radial-gradient(circle at 90%, #e23fe2 10px, #000 10px, #000 11px, transparent 11px), #00D900 """ def genSegmentsTable(obj): segments = [] if obj is not None and obj["Count"] is not None: for i in range(1, obj["Count"]+1): dint = "DINT"+str(int(i/8)) if obj[dint] is not None: percent = extractNibble(obj[dint], i % 8) / 15.0 segments.append([i, percent]) return system.dataset.toDataSet(["segment", "fill"], segments) def genSegmentColor(data): perc = (data/15.0) c1 = 255 - (255 - 217)*perc c2 = 255 - (255 - 0)*perc return "rgb(%s, %s, %s)" % (c1, c2, c1) def genSegmentsPattern(obj): if obj["Count"] is not None and obj["Count"] > 0: percUnit = 100 / float(obj["Count"]) gradients = [] for i in range(1, obj["Count"]+1): dint = "DINT"+str(int(i/8)) if obj[dint] is not None: data = extractNibble(obj[dint], i % 8) color = genSegmentColor(data) circlePos = ((obj["Count"]-i))*percUnit + percUnit/2.0 perc = (data/15.0*0.5+0.5) if data > 0 else 0.0 # Make circle size between 50%-100% if perc > 0.0: output = "radial-gradient(circle at %s%%" % (circlePos) output += ", %s calc((var(--conv-width) - 8px)/2*%s)" % (color, perc) output += ", #000 calc((var(--conv-width) - 8px)/2*%s)" % (perc) output += ", #000 calc((var(--conv-width) - 8px)/2*%s + 1px)" % (perc) output += ", transparent calc((var(--conv-width) - 8px)/2*%s + 1px)" % (perc) output += ")" gradients.append(output) if len(gradients) > 0: return ", ".join(gradients)+"," return "" def genSegmentsTooltip(obj): if obj["Count"] is not None and obj["Count"] > 0: data = extractNibble(obj["DINT0"], 0) output = "

SegmentAVG: %s%%" % (int(round(100 * data / 15.0))) for i in range(1, obj["Count"]+1): dint = "DINT"+str(int(i/8)) if obj[dint] is not None: data = extractNibble(obj[dint], i % 8) output += "
Segment%s: %s%%" % (i, int(round(100 * data / 15.0))) return output return "" def genSegmentHeatmap(obj): segments = [] if obj["Count"] is not None and obj["Count"] > 0: for i in range(1, obj["Count"]+1): dint = "DINT"+str(int(i/8)) if obj[dint] is not None: data = extractNibble(obj[dint], i % 8) color = 255 * data / 15 segments.append("rgb(255, %s, %s)" % (color, color)) return json.dumps(segments)