Skip to content

Commit

Permalink
updated to 0.7.0rc7
Browse files Browse the repository at this point in the history
0.7.0rc7
- added admin for VariableProperty
- added capability of reading and writing VariableProperties from the
HMI and devices
- altered arguents for device.write_data!
  • Loading branch information
trombastic committed Jun 29, 2018
1 parent 94f8dbf commit 3214e33
Show file tree
Hide file tree
Showing 18 changed files with 292 additions and 84 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -7,3 +7,4 @@ PyScada.egg-info
dist
/.project
docs/_build
/.idea/*
7 changes: 6 additions & 1 deletion CHANGELOG.txt
Expand Up @@ -150,4 +150,9 @@
0.7.0rc6
- corrected typos
- fixes of AppConfig for setup.py develop
- added protocol id for scripting extension
- added protocol id for scripting extension

0.7.0rc7
- added admin for VariableProperty
- added capability of reading and writing VariableProperties from the HMI and devices
- altered arguents for device.write_data!
13 changes: 12 additions & 1 deletion pyscada/admin.py
Expand Up @@ -2,7 +2,7 @@
from __future__ import unicode_literals

from pyscada.models import Device, DeviceProtocol
from pyscada.models import Variable
from pyscada.models import Variable, VariableProperty
from pyscada.models import Scaling, Color
from pyscada.models import Unit
from pyscada.models import DeviceWriteTask
Expand Down Expand Up @@ -211,9 +211,20 @@ class EventAdmin(admin.ModelAdmin):
raw_id_fields = ('variable',)


class VariablePropertyAdmin(admin.ModelAdmin):
list_display = ('id','variable','name','property_class', 'value','timestamp')
list_display_links = ('id','variable','name','property_class')
list_filter = ('variable', 'name', 'property_class',)
raw_id_fields = ('variable',)

def value(self, instance):
return instance.value()


admin_site = PyScadaAdminSite(name='pyscada_admin')
admin_site.register(Device, DeviceAdmin)
admin_site.register(Variable, CoreVariableAdmin)
admin_site.register(VariableProperty, VariablePropertyAdmin)
admin_site.register(Scaling)
admin_site.register(Unit)
admin_site.register(Event, EventAdmin)
Expand Down
2 changes: 1 addition & 1 deletion pyscada/core/__init__.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

__version__ = '0.7.0rc6'
__version__ = '0.7.0rc7'
__author__ = 'Martin Schröder'

default_app_config = 'pyscada.apps.PyScadaConfig'
Expand Down
20 changes: 20 additions & 0 deletions pyscada/hmi/migrations/0009_controlitem_property_name.py
@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.13 on 2018-06-29 10:15
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('hmi', '0008_auto_20180620_0716'),
]

operations = [
migrations.AddField(
model_name='controlitem',
name='property_name',
field=models.CharField(blank=True, default='', max_length=255),
),
]
8 changes: 7 additions & 1 deletion pyscada/hmi/models.py
Expand Up @@ -28,16 +28,22 @@ class ControlItem(models.Model):
(6, 'Display Value'),)
type = models.PositiveSmallIntegerField(default=0, choices=type_choices)
variable = models.ForeignKey(Variable, null=True)
property_name = models.CharField(default='', blank=True, max_length=255)

class Meta:
ordering = ['position']

def __str__(self):
return (self.label + " (" + self.variable.name + ")")
return self.label + " (" + self.variable.name + ")"

def web_id(self):
return self.id.__str__() + "-" + self.variable.name.replace(' ', '_')

def web_class_str(self):
if self.property_name == '':
return 'var-%d'%self.variable_id
else:
return 'prop-%d-%s' % (self.variable_id, self.property_name.lower().replace(':','-'))

@python_2_unicode_compatible
class Chart(models.Model):
Expand Down
85 changes: 49 additions & 36 deletions pyscada/hmi/static/pyscada/js/pyscada/pyscada.js
@@ -1,12 +1,12 @@
/* Javascript library for the PyScada web client based on jquery and flot,
version 0.7.0rc2
version 0.7.0rc7
Copyright (c) 2013-2018 Martin Schröder
Licensed under the GPL.
*/
var version = "0.7.0rc2"
var version = "0.7.0rc7"
var NOTIFICATION_COUNT = 0
var UPDATE_STATUS_COUNT = 0;
var INIT_STATUS_COUNT = 0;
Expand Down Expand Up @@ -34,6 +34,7 @@ var VARIABLE_KEYS = [];
var STATUS_VARIABLE_KEYS = {count:function(){var c = 0;for (key in this){c++;} return c-2;},keys:function(){var k = [];for (key in this){if (key !=="keys" && key !=="count"){k.push(key);}} return k;}};
var CHART_VARIABLE_KEYS = {count:function(){var c = 0;for (key in this){c++;} return c-2;},keys:function(){var k = [];for (key in this){if (key !=="keys" && key !=="count"){k.push(key);}} return k;}};
var DATA = {}; // holds the fetched data from the server
var VARIABLE_PROPERTIES = {};
var DATA_INIT_STATUS = 0; // status 0: nothing done, 1:
var UPDATE_X_AXES_TIME_LINE_STATUS = false;
var FETCH_DATA_PENDING = 0;
Expand Down Expand Up @@ -249,6 +250,12 @@ function data_handler_done(fetched_data){
}else{
SERVER_TIME = 0;
}
if (typeof(fetched_data['variable_properties'])==="object"){
VARIABLE_PROPERTIES = fetched_data['variable_properties'];
delete fetched_data['variable_properties'];
}else{
VARIABLE_PROPERTIES = {}
}
if(DATA_TO_TIMESTAMP==0){
DATA_TO_TIMESTAMP = DATA_FROM_TIMESTAMP = SERVER_TIME;
}else{
Expand Down Expand Up @@ -282,9 +289,13 @@ function data_handler_done(fetched_data){
for (var key in VARIABLE_KEYS) {
key = VARIABLE_KEYS[key];
if (typeof(DATA[key]) == 'object'){
update_data_values(key,DATA[key][DATA[key].length-1][1]);
update_data_values('var-' + key,DATA[key][DATA[key].length-1][1]);
}
}
for (var key in VARIABLE_PROPERTIES) {
value = VARIABLE_PROPERTIES[key];
update_data_values('prop-' + key.toLowerCase(),value);
}
/*
DATA_OUT_OF_DATE = (SERVER_TIME - timestamp > CACHE_TIMEOUT);
if (DATA_OUT_OF_DATE){
Expand Down Expand Up @@ -472,47 +483,47 @@ function update_data_values(key,val){
}else{
r_val = r_val.toPrecision(4);
}
$(".type-numeric.var-" + key).html(r_val);
$('input.var-'+ key).attr("placeholder",r_val);
$(".type-numeric." + key).html(r_val);
$('input.'+ key).attr("placeholder",r_val);
// unixtime
var date = new Date(val*1000);
$(".type-numeric.unixtime_local_date_time.var-" + key).html(date.toLocaleString());
$(".type-numeric.unixtime_utc_date_time.var-" + key).html(date.toUTCString());
$(".type-numeric.hex_str_full.var-" + key).html(val.toString(16).toUpperCase());
$(".type-numeric.unixtime_local_date_time." + key).html(date.toLocaleString());
$(".type-numeric.unixtime_utc_date_time." + key).html(date.toUTCString());
$(".type-numeric.hex_str_full." + key).html(val.toString(16).toUpperCase());
}

// set value fields
if (typeof(val)==="boolean"){
// set button colors
if (val === 0 | val == false) {
$(".label.type-bool.var-" + key).addClass("label-default");
$(".label.type-bool.var-" + key).removeClass("label-primary");
$(".label.type-bool.var-" + key).removeClass("label-info");
$(".label.type-bool.var-" + key).removeClass("label-success");
$(".label.type-bool.var-" + key).removeClass("label-warning");
$(".label.type-bool.var-" + key).removeClass("label-danger");
$(".label.type-bool." + key).addClass("label-default");
$(".label.type-bool." + key).removeClass("label-primary");
$(".label.type-bool." + key).removeClass("label-info");
$(".label.type-bool." + key).removeClass("label-success");
$(".label.type-bool." + key).removeClass("label-warning");
$(".label.type-bool." + key).removeClass("label-danger");
// inverted
$(".label.type-bool.status-red-inv.var-" + key).addClass("label-danger");
$(".label.type-bool.status-red-inv." + key).addClass("label-danger");

$('button.btn-default.write-task-btn.var-' + key).addClass("updateable");
$('button.updateable.write-task-btn.var-' + key).addClass("btn-default");
$('button.updateable.write-task-btn.var-' + key).removeClass("btn-success");
$(".type-numeric.var-" + key).html(0);
$('input.var-'+ key).attr("placeholder",0);
$('button.btn-default.write-task-btn.' + key).addClass("updateable");
$('button.updateable.write-task-btn.' + key).addClass("btn-default");
$('button.updateable.write-task-btn.' + key).removeClass("btn-success");
$(".type-numeric." + key).html(0);
$('input.'+ key).attr("placeholder",0);
} else {
$(".label.type-bool.var-" + key).removeClass("label-default");
$(".label.type-bool.var-" + key).removeClass("label-danger");
$(".label.type-bool.status-blue.var-" + key).addClass("label-primary");
$(".label.type-bool.status-info.var-" + key).addClass("label-info");
$(".label.type-bool.status-green.var-" + key).addClass("label-success");
$(".label.type-bool.status-yello.var-" + key).addClass("label-warning");
$(".label.type-bool.status-red.var-" + key).addClass("label-danger");
$(".label.type-bool.status-red-inv.var-" + key).addClass("label-default");
$('button.btn-success.write-task-btn.var-' + key).addClass("updateable");
$('button.updateable.write-task-btn.var-' + key).removeClass("btn-default");
$('button.updateable.write-task-btn.var-' + key).addClass("btn-success");
$(".type-numeric.var-" + key).html(1);
$('input.var-'+ key).attr("placeholder",1);
$(".label.type-bool." + key).removeClass("label-default");
$(".label.type-bool." + key).removeClass("label-danger");
$(".label.type-bool.status-blue." + key).addClass("label-primary");
$(".label.type-bool.status-info." + key).addClass("label-info");
$(".label.type-bool.status-green." + key).addClass("label-success");
$(".label.type-bool.status-yello." + key).addClass("label-warning");
$(".label.type-bool.status-red." + key).addClass("label-danger");
$(".label.type-bool.status-red-inv." + key).addClass("label-default");
$('button.btn-success.write-task-btn.' + key).addClass("updateable");
$('button.updateable.write-task-btn.' + key).removeClass("btn-default");
$('button.updateable.write-task-btn.' + key).addClass("btn-success");
$(".type-numeric." + key).html(1);
$('input.'+ key).attr("placeholder",1);
}
}
}
Expand Down Expand Up @@ -932,13 +943,14 @@ $('button.write-task-set').click(function(){
var_id = $(this).attr('var_id');
id = $(this).attr('id');
value = $("#"+id+"-value").val();
property_name = $(this).attr('property_name');
if (value == "" ){
add_notification('please provide a value',3);
}else{
$.ajax({
type: 'post',
url: ROOT_URL+'form/write_task/',
data: {var_id:var_id,value:value},
data: {var_id:var_id,value:value,property_name:property_name},
success: function (data) {

},
Expand All @@ -952,12 +964,13 @@ $('button.write-task-set').click(function(){
$('button.write-task-btn').click(function(){
var_id = $(this).attr('var_id');
id = $(this).attr('id');
property_name = $(this).attr('property_name');
$('#'+id).removeClass('updateable');
if($(this).hasClass('btn-default')){
$.ajax({
type: 'post',
url: ROOT_URL+'form/write_task/',
data: {var_id:var_id,value:1},
data: {var_id:var_id,value:1,property_name:property_name},
success: function (data) {
$('#'+id).removeClass('btn-default')
$('#'+id).addClass('btn-success');
Expand All @@ -970,7 +983,7 @@ $('button.write-task-btn').click(function(){
$.ajax({
type: 'post',
url: ROOT_URL+'form/write_task/',
data: {var_id:var_id,value:0},
data: {var_id:var_id,value:0,property_name:property_name},
success: function (data) {
$('#'+id).addClass('btn-default')
$('#'+id).removeClass('btn-success');
Expand Down
20 changes: 10 additions & 10 deletions pyscada/hmi/templates/control_element.html
@@ -1,31 +1,31 @@
{% if item.variable.active == 1 and item.variable.device.active == 1 %}
<div class="hidden variable-config" data-name="{{ item.variable.name }}" data-key="{{ item.variable.pk }}" data-init-type="0"></div>
{% if item.type == 0 %}<!-- label blue -->
<div class="input-group control_label"><span class="label label-default type-bool status-green var-{{ item.variable.pk }}">{{ item.label }}</span></div>
<div class="input-group control_label"><span class="label label-default type-bool status-green {{ item.web_class_str }}">{{ item.label }}</span></div>
{% elif item.type == 1 %}<!-- label light blue -->
<div class="input-group control_label"><span class="label label-default type-bool status-green var-{{ item.variable.pk }}">{{ item.label }}</span></div>
<div class="input-group control_label"><span class="label label-default type-bool status-green {{ item.web_class_str }}">{{ item.label }}</span></div>
{% elif item.type == 2 %}<!-- label ok -->
<div class="input-group control_label"><span class="label label-default type-bool status-green var-{{ item.variable.pk }}">{{ item.label }}</span></div>
<div class="input-group control_label"><span class="label label-default type-bool status-green {{ item.web_class_str }}">{{ item.label }}</span></div>
{% elif item.type == 3 %}<!-- label warning -->
<div class="input-group control_label"><span class="label label-default type-bool status-yello var-{{ item.variable.pk }}">{{ item.label }}</span></div>
<div class="input-group control_label"><span class="label label-default type-bool status-yello {{ item.web_class_str }}">{{ item.label }}</span></div>
{% elif item.type == 4 %}<!-- label alarm -->
<div class="input-group control_label"><span class="label label-default type-bool status-red var-{{ item.variable.pk }}">{{ item.label }}</span></div>
<div class="input-group control_label"><span class="label label-default type-bool status-red {{ item.web_class_str }}">{{ item.label }}</span></div>
{% elif item.type == 7 %}<!-- label alarm inverted -->
<div class="input-group control_label"><span class="label label-default type-bool status-red-inv var-{{ item.variable.pk }}">{{ item.label }}</span></div>
<div class="input-group control_label"><span class="label label-default type-bool status-red-inv {{ item.web_class_str }}">{{ item.label }}</span></div>
{% elif item.type == 5 %}<!-- input -->
{% if item.variable.value_class == 'BOOL' or item.variable.value_class == 'BOOLEAN' %}
<div class="input-group control_button"><button type="button" var_id="{{ item.variable.pk }}" class="btn btn-default updateable write-task-btn type-bool var-{{ item.variable.pk }}" id="{{ item.web_id }}">{{ item.label }}</button></div>
<div class="input-group control_button"><button type="button" var_id="{{ item.variable.pk }}" property_name="{{ item.property_name }}" class="btn btn-default updateable write-task-btn type-bool {{ item.web_class_str }}" id="{{ item.web_id }}">{{ item.label }}</button></div>
{% else %}
<div class="input-group set_value">
<span class="input-group-addon input-group-addon-label">{{ item.label }}</span>
<input type="text" class="form-control var-{{ item.variable.pk }}" id="{{ item.web_id }}-value" placeholder="">
<input type="text" class="form-control {{ item.web_class_str }}" id="{{ item.web_id }}-value" placeholder="">
<span class="input-group-addon">{{ item.variable.unit.unit }}</span>
<span class="input-group-btn">
<button class="btn btn-default write-task-set set-{{ item.variable.pk }}" var_id="{{ item.variable.pk }}" id="{{ item.web_id }}" type="button">set</button>
<button class="btn btn-default write-task-set set-{{ item.variable.pk }}" var_id="{{ item.variable.pk }}" property_name="{{ item.property_name }}" id="{{ item.web_id }}" type="button">set</button>
</span>
</div>
{% endif %}
{% elif item.type == 6 %}<!-- display value -->
<div class="input-group control_label"><span class="type-label">{{ item.label }}<span class="type-unit"><span class="type-numeric var-{{ item.variable.pk }}">NaN</span> {{ item.variable.unit.unit }}</span></span></div>
<div class="input-group control_label"><span class="type-label">{{ item.label }}<span class="type-unit"><span class="type-numeric {{ item.web_class_str }}">NaN</span> {{ item.variable.unit.unit }}</span></span></div>
{% endif %}
{% endif %}
13 changes: 9 additions & 4 deletions pyscada/hmi/views.py
Expand Up @@ -2,7 +2,7 @@
from __future__ import unicode_literals

from pyscada.core import version as core_version
from pyscada.models import RecordedData
from pyscada.models import RecordedData, VariableProperty
from pyscada.hmi.models import Chart
from pyscada.hmi.models import ControlItem
from pyscada.hmi.models import CustomHTMLPanel
Expand Down Expand Up @@ -165,7 +165,8 @@ def form_write_task(request):
return redirect('/accounts/login/?next=%s' % request.path)
if 'var_id' in request.POST and 'value' in request.POST:
cwt = DeviceWriteTask(variable_id=request.POST['var_id'], value=request.POST['value'], start=time.time(),
user=request.user)
user=request.user,
property_name=request.POST['property_name'] if 'property_name' in request.POST else '',)
cwt.save()
return HttpResponse(status=200)
else:
Expand Down Expand Up @@ -211,7 +212,7 @@ def get_cache_data(request):
timestamp_from == time.time()-60

if timestamp_to - timestamp_from > 120*60:
timestamp_from = timestamp_to -120*60
timestamp_from = timestamp_to - 120*60

data = RecordedData.objects.get_values_in_time_range(
time_min=timestamp_from,
Expand All @@ -225,7 +226,11 @@ def get_cache_data(request):
add_latest_value=False)

if data is None:
return HttpResponse(json.dumps({'server_time': time.time() * 1000}), content_type='application/json')
data = {}
data['variable_properties'] = {}
for item in VariableProperty.objects.filter(variable_id__in=active_variables):
data['variable_properties'][item.web_key()] = item.value()

data["server_time"] = time.time() * 1000
return HttpResponse(json.dumps(data), content_type='application/json')

Expand Down
2 changes: 1 addition & 1 deletion pyscada/modbus/device.py
Expand Up @@ -311,7 +311,7 @@ def request_data(self):
self._disconnect()
return output

def write_data(self, variable_id, value):
def write_data(self, variable_id, value, task):
"""
write value to single modbus register or coil
"""
Expand Down

0 comments on commit 3214e33

Please sign in to comment.