PyAutomationIO 1.0.3__tar.gz → 1.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/PKG-INFO +1 -1
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/PyAutomationIO.egg-info/PKG-INFO +1 -1
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/core.py +17 -2
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/dbmodels/alarms.py +30 -5
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/dbmodels/events.py +30 -5
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/logger/alarms.py +11 -3
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/logger/datalogger.py +234 -3
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/logger/events.py +11 -3
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/modules/alarms/resources/summary.py +3 -1
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/modules/events/resources/events.py +3 -1
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/modules/tags/resources/tags.py +53 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/state_machine.py +2 -0
- pyautomationio-1.1.1/version.py +2 -0
- pyautomationio-1.0.3/version.py +0 -2
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/LICENSE +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/MANIFEST.in +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/PyAutomationIO.egg-info/SOURCES.txt +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/PyAutomationIO.egg-info/dependency_links.txt +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/PyAutomationIO.egg-info/requires.txt +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/PyAutomationIO.egg-info/top_level.txt +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/README.md +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/__init__.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/alarms/__init__.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/alarms/states.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/alarms/trigger.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/buffer.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/dbmodels/__init__.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/dbmodels/core.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/dbmodels/logs.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/dbmodels/machines.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/dbmodels/opcua.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/dbmodels/opcua_server.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/dbmodels/tags.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/dbmodels/users.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/extensions/__init__.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/extensions/api.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/extensions/cors.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/filter/__init__.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/iad/__init__.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/iad/frozen_data.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/iad/out_of_range.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/iad/outliers.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/logger/__init__.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/logger/core.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/logger/logdict.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/logger/logs.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/logger/machines.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/logger/opcua_server.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/logger/users.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/managers/__init__.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/managers/alarms.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/managers/db.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/managers/opcua_client.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/managers/state_machine.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/models.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/modules/__init__.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/modules/alarms/__init__.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/modules/alarms/resources/__init__.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/modules/alarms/resources/alarms.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/modules/events/__init__.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/modules/events/resources/__init__.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/modules/events/resources/logs.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/modules/tags/__init__.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/modules/tags/resources/__init__.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/modules/users/__init__.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/modules/users/resources/__init__.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/modules/users/resources/models/__init__.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/modules/users/resources/models/roles.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/modules/users/resources/models/users.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/modules/users/resources/roles.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/modules/users/resources/users.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/modules/users/roles.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/modules/users/users.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/opcua/__init__.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/opcua/models.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/opcua/subscription.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/__init__.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/alarms.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/alarms_history.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/assets/styles.css +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/callbacks/__init__.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/callbacks/alarms.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/callbacks/alarms_summary.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/callbacks/db.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/callbacks/filter.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/callbacks/machines.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/callbacks/machines_detailed.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/callbacks/opcua.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/callbacks/opcua_server.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/callbacks/tags.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/callbacks/trends.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/communications.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/components/__init__.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/components/alarms.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/components/alarms_summary.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/components/database.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/components/gaussian_filter.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/components/machines.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/components/opcua.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/components/opcua_server.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/components/tags.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/components/trends.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/database.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/filter.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/machines.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/machines_detailed.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/main.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/opcua_server.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/tags.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/trends.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/singleton.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/tags/__init__.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/tags/cvt.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/tags/filter.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/tags/tag.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/tests/__init__.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/tests/test_alarms.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/tests/test_core.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/tests/test_unit.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/tests/test_user.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/utils/__init__.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/utils/decorators.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/utils/npw.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/utils/observer.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/utils/units.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/variables/__init__.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/variables/adimentional.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/variables/current.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/variables/density.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/variables/eng_time.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/variables/force.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/variables/length.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/variables/mass.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/variables/mass_flow.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/variables/percentage.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/variables/power.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/variables/pressure.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/variables/temperature.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/variables/volume.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/variables/volumetric_flow.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/workers/__init__.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/workers/logger.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/workers/state_machine.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/workers/worker.py +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/requirements.txt +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/setup.cfg +0 -0
- {pyautomationio-1.0.3 → pyautomationio-1.1.1}/setup.py +0 -0
|
@@ -373,6 +373,13 @@ class PyAutomation(Singleton):
|
|
|
373
373
|
"""
|
|
374
374
|
return self.logger_engine.read_table(start, stop, timezone, tags, page, limit)
|
|
375
375
|
|
|
376
|
+
@logging_error_handler
|
|
377
|
+
def get_tabular_data(self, start:str, stop:str, timezone:str, tags:list, sample_time:int, page:int=1, limit:int=20):
|
|
378
|
+
r"""
|
|
379
|
+
Documentation here
|
|
380
|
+
"""
|
|
381
|
+
return self.logger_engine.read_tabular_data(start, stop, timezone, tags, sample_time, page, limit)
|
|
382
|
+
|
|
376
383
|
@logging_error_handler
|
|
377
384
|
def get_segments(self):
|
|
378
385
|
r"""
|
|
@@ -1363,6 +1370,10 @@ class PyAutomation(Singleton):
|
|
|
1363
1370
|
Documentation here
|
|
1364
1371
|
"""
|
|
1365
1372
|
if self.is_db_connected():
|
|
1373
|
+
|
|
1374
|
+
# Ensure pagination parameters are present or defaulted
|
|
1375
|
+
if 'page' not in fields: fields['page'] = 1
|
|
1376
|
+
if 'limit' not in fields: fields['limit'] = 20
|
|
1366
1377
|
|
|
1367
1378
|
return self.alarms_engine.filter_alarm_summary_by(**fields)
|
|
1368
1379
|
|
|
@@ -1535,7 +1546,9 @@ class PyAutomation(Singleton):
|
|
|
1535
1546
|
description:str="",
|
|
1536
1547
|
greater_than_timestamp:datetime=None,
|
|
1537
1548
|
less_than_timestamp:datetime=None,
|
|
1538
|
-
timezone:str="UTC"
|
|
1549
|
+
timezone:str="UTC",
|
|
1550
|
+
page:int=1,
|
|
1551
|
+
limit:int=20)->list:
|
|
1539
1552
|
r"""
|
|
1540
1553
|
Documentation here
|
|
1541
1554
|
"""
|
|
@@ -1550,7 +1563,9 @@ class PyAutomation(Singleton):
|
|
|
1550
1563
|
classification=classification,
|
|
1551
1564
|
greater_than_timestamp=greater_than_timestamp,
|
|
1552
1565
|
less_than_timestamp=less_than_timestamp,
|
|
1553
|
-
timezone=timezone
|
|
1566
|
+
timezone=timezone,
|
|
1567
|
+
page=page,
|
|
1568
|
+
limit=limit
|
|
1554
1569
|
)
|
|
1555
1570
|
|
|
1556
1571
|
return list()
|
|
@@ -448,11 +448,14 @@ class AlarmSummary(BaseModel):
|
|
|
448
448
|
tags:list[str]=None,
|
|
449
449
|
greater_than_timestamp:datetime=None,
|
|
450
450
|
less_than_timestamp:datetime=None,
|
|
451
|
-
timezone:str='UTC'
|
|
451
|
+
timezone:str='UTC',
|
|
452
|
+
page:int=1,
|
|
453
|
+
limit:int=20
|
|
452
454
|
):
|
|
453
455
|
r"""
|
|
454
456
|
Documentation here
|
|
455
457
|
"""
|
|
458
|
+
import math
|
|
456
459
|
_timezone = pytz.timezone(timezone)
|
|
457
460
|
query = cls.select()
|
|
458
461
|
|
|
@@ -478,11 +481,33 @@ class AlarmSummary(BaseModel):
|
|
|
478
481
|
query = query.where(cls.alarm_time < less_than_timestamp)
|
|
479
482
|
|
|
480
483
|
query = query.order_by(cls.id.desc())
|
|
481
|
-
if not query.exists():
|
|
482
|
-
|
|
483
|
-
return []
|
|
484
484
|
|
|
485
|
-
|
|
485
|
+
total_records = query.count()
|
|
486
|
+
|
|
487
|
+
if limit <= 0: limit = 20
|
|
488
|
+
if page <= 0: page = 1
|
|
489
|
+
|
|
490
|
+
total_pages = math.ceil(total_records / limit)
|
|
491
|
+
if total_pages == 0: total_pages = 1
|
|
492
|
+
|
|
493
|
+
has_next = page < total_pages
|
|
494
|
+
has_prev = page > 1
|
|
495
|
+
|
|
496
|
+
paginated_query = query.paginate(page, limit)
|
|
497
|
+
|
|
498
|
+
data = [alarm.serialize() for alarm in paginated_query]
|
|
499
|
+
|
|
500
|
+
return {
|
|
501
|
+
"data": data,
|
|
502
|
+
"pagination": {
|
|
503
|
+
"page": page,
|
|
504
|
+
"limit": limit,
|
|
505
|
+
"total_records": total_records,
|
|
506
|
+
"total_pages": total_pages,
|
|
507
|
+
"has_next": has_next,
|
|
508
|
+
"has_prev": has_prev
|
|
509
|
+
}
|
|
510
|
+
}
|
|
486
511
|
|
|
487
512
|
@classmethod
|
|
488
513
|
def get_alarm_summary_comments(cls, id:int):
|
|
@@ -77,10 +77,14 @@ class Events(BaseModel):
|
|
|
77
77
|
description:str="",
|
|
78
78
|
message:str="",
|
|
79
79
|
classification:str="",
|
|
80
|
-
timezone:str='UTC'
|
|
80
|
+
timezone:str='UTC',
|
|
81
|
+
page:int=1,
|
|
82
|
+
limit:int=20
|
|
83
|
+
):
|
|
81
84
|
r"""
|
|
82
85
|
Documentation here
|
|
83
86
|
"""
|
|
87
|
+
import math
|
|
84
88
|
_timezone = pytz.timezone(timezone)
|
|
85
89
|
query = cls.select()
|
|
86
90
|
|
|
@@ -113,11 +117,32 @@ class Events(BaseModel):
|
|
|
113
117
|
|
|
114
118
|
query = query.order_by(cls.id.desc())
|
|
115
119
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
120
|
+
total_records = query.count()
|
|
121
|
+
|
|
122
|
+
if limit <= 0: limit = 20
|
|
123
|
+
if page <= 0: page = 1
|
|
124
|
+
|
|
125
|
+
total_pages = math.ceil(total_records / limit)
|
|
126
|
+
if total_pages == 0: total_pages = 1
|
|
127
|
+
|
|
128
|
+
has_next = page < total_pages
|
|
129
|
+
has_prev = page > 1
|
|
119
130
|
|
|
120
|
-
|
|
131
|
+
paginated_query = query.paginate(page, limit)
|
|
132
|
+
|
|
133
|
+
data = [event.serialize() for event in paginated_query]
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
"data": data,
|
|
137
|
+
"pagination": {
|
|
138
|
+
"page": page,
|
|
139
|
+
"limit": limit,
|
|
140
|
+
"total_records": total_records,
|
|
141
|
+
"total_pages": total_pages,
|
|
142
|
+
"has_next": has_next,
|
|
143
|
+
"has_prev": has_prev
|
|
144
|
+
}
|
|
145
|
+
}
|
|
121
146
|
|
|
122
147
|
@classmethod
|
|
123
148
|
def get_comments(cls, id:int):
|
|
@@ -119,7 +119,9 @@ class AlarmsLogger(BaseLogger):
|
|
|
119
119
|
tags:list[str]=None,
|
|
120
120
|
greater_than_timestamp:datetime=None,
|
|
121
121
|
less_than_timestamp:datetime=None,
|
|
122
|
-
timezone:str="UTC"
|
|
122
|
+
timezone:str="UTC",
|
|
123
|
+
page:int=1,
|
|
124
|
+
limit:int=20
|
|
123
125
|
):
|
|
124
126
|
r"""
|
|
125
127
|
Documentation here
|
|
@@ -138,7 +140,9 @@ class AlarmsLogger(BaseLogger):
|
|
|
138
140
|
tags=tags,
|
|
139
141
|
greater_than_timestamp=greater_than_timestamp,
|
|
140
142
|
less_than_timestamp=less_than_timestamp,
|
|
141
|
-
timezone=timezone
|
|
143
|
+
timezone=timezone,
|
|
144
|
+
page=page,
|
|
145
|
+
limit=limit
|
|
142
146
|
)
|
|
143
147
|
|
|
144
148
|
@db_rollback
|
|
@@ -326,7 +330,9 @@ class AlarmsLoggerEngine(BaseEngine):
|
|
|
326
330
|
tags:list[int]=None,
|
|
327
331
|
greater_than_timestamp:datetime=None,
|
|
328
332
|
less_than_timestamp:datetime=None,
|
|
329
|
-
timezone:str='UTC'
|
|
333
|
+
timezone:str='UTC',
|
|
334
|
+
page:int=1,
|
|
335
|
+
limit:int=20
|
|
330
336
|
):
|
|
331
337
|
|
|
332
338
|
_query = dict()
|
|
@@ -338,6 +344,8 @@ class AlarmsLoggerEngine(BaseEngine):
|
|
|
338
344
|
_query["parameters"]["greater_than_timestamp"] = greater_than_timestamp
|
|
339
345
|
_query["parameters"]["less_than_timestamp"] = less_than_timestamp
|
|
340
346
|
_query["parameters"]["timezone"] = timezone
|
|
347
|
+
_query["parameters"]["page"] = page
|
|
348
|
+
_query["parameters"]["limit"] = limit
|
|
341
349
|
|
|
342
350
|
return self.query(_query)
|
|
343
351
|
|
|
@@ -5,6 +5,7 @@ This module implements a database logger for the CVT instance,
|
|
|
5
5
|
will create a time-serie for each tag in a short memory data base.
|
|
6
6
|
"""
|
|
7
7
|
import pytz, logging, math
|
|
8
|
+
from peewee import fn
|
|
8
9
|
from collections import defaultdict
|
|
9
10
|
from datetime import datetime
|
|
10
11
|
from ..tags.tag import Tag
|
|
@@ -388,6 +389,235 @@ class DataLogger(BaseLogger):
|
|
|
388
389
|
}
|
|
389
390
|
}
|
|
390
391
|
|
|
392
|
+
@db_rollback
|
|
393
|
+
def read_tabular_data(self, start:str, stop:str, timezone:str, tags:list, sample_time:int, page:int=1, limit:int=20):
|
|
394
|
+
r"""
|
|
395
|
+
Get historical data in tabular format with pagination and forward-fill resampling.
|
|
396
|
+
|
|
397
|
+
Args:
|
|
398
|
+
start (str): Start datetime string
|
|
399
|
+
stop (str): Stop datetime string
|
|
400
|
+
timezone (str): Timezone string
|
|
401
|
+
tags (list): List of tag names
|
|
402
|
+
sample_time (int): Sample time in seconds
|
|
403
|
+
page (int): Page number
|
|
404
|
+
limit (int): Items per page
|
|
405
|
+
|
|
406
|
+
Returns:
|
|
407
|
+
dict: {
|
|
408
|
+
"data": [...],
|
|
409
|
+
"pagination": {...}
|
|
410
|
+
}
|
|
411
|
+
"""
|
|
412
|
+
if not self.is_history_logged:
|
|
413
|
+
return None
|
|
414
|
+
|
|
415
|
+
if not self.check_connectivity():
|
|
416
|
+
return dict()
|
|
417
|
+
|
|
418
|
+
_timezone = pytz.timezone(timezone)
|
|
419
|
+
utc_timezone = pytz.UTC
|
|
420
|
+
|
|
421
|
+
try:
|
|
422
|
+
start_dt = _timezone.localize(datetime.strptime(start, DATETIME_FORMAT)).astimezone(utc_timezone)
|
|
423
|
+
stop_dt = _timezone.localize(datetime.strptime(stop, DATETIME_FORMAT)).astimezone(utc_timezone)
|
|
424
|
+
start_ts = start_dt.timestamp()
|
|
425
|
+
stop_ts = stop_dt.timestamp()
|
|
426
|
+
except ValueError:
|
|
427
|
+
return dict()
|
|
428
|
+
|
|
429
|
+
if sample_time <= 0:
|
|
430
|
+
return dict()
|
|
431
|
+
|
|
432
|
+
# Check for data presence to adjust start time if necessary
|
|
433
|
+
# 1. Check if there is any data BEFORE or AT start_dt (history)
|
|
434
|
+
has_history = (TagValue
|
|
435
|
+
.select()
|
|
436
|
+
.join(Tags)
|
|
437
|
+
.where(
|
|
438
|
+
(Tags.name.in_(tags)) &
|
|
439
|
+
(TagValue.timestamp <= start_dt)
|
|
440
|
+
)
|
|
441
|
+
.limit(1)
|
|
442
|
+
.count() > 0)
|
|
443
|
+
|
|
444
|
+
if not has_history:
|
|
445
|
+
# 2. If no history, find the first actual data point within the requested range
|
|
446
|
+
min_ts = (TagValue
|
|
447
|
+
.select(fn.Min(TagValue.timestamp))
|
|
448
|
+
.join(Tags)
|
|
449
|
+
.where(
|
|
450
|
+
(Tags.name.in_(tags)) &
|
|
451
|
+
(TagValue.timestamp >= start_dt) &
|
|
452
|
+
(TagValue.timestamp <= stop_dt) &
|
|
453
|
+
(TagValue.value.is_null(False))
|
|
454
|
+
)
|
|
455
|
+
.scalar())
|
|
456
|
+
|
|
457
|
+
if min_ts is None:
|
|
458
|
+
# No data in range and no history
|
|
459
|
+
return {"data": [], "pagination": {}}
|
|
460
|
+
|
|
461
|
+
# Adjust start to the first actual data point
|
|
462
|
+
# Ensure min_ts is timezone aware if needed, though scalar() returns DB format
|
|
463
|
+
if isinstance(min_ts, datetime):
|
|
464
|
+
if min_ts.tzinfo is None:
|
|
465
|
+
min_ts = utc_timezone.localize(min_ts)
|
|
466
|
+
start_dt = min_ts
|
|
467
|
+
start_ts = start_dt.timestamp()
|
|
468
|
+
elif isinstance(min_ts, (int, float)):
|
|
469
|
+
start_ts = float(min_ts)
|
|
470
|
+
start_dt = datetime.fromtimestamp(start_ts, pytz.UTC)
|
|
471
|
+
|
|
472
|
+
# Calculate total records based on time range and sample time
|
|
473
|
+
total_duration = stop_ts - start_ts
|
|
474
|
+
if total_duration < 0:
|
|
475
|
+
return {"data": [], "pagination": {}}
|
|
476
|
+
|
|
477
|
+
total_records = math.floor(total_duration / sample_time) + 1
|
|
478
|
+
|
|
479
|
+
# Pagination calculations
|
|
480
|
+
if limit <= 0: limit = 20
|
|
481
|
+
if page <= 0: page = 1
|
|
482
|
+
|
|
483
|
+
total_pages = math.ceil(total_records / limit)
|
|
484
|
+
if total_pages == 0: total_pages = 1
|
|
485
|
+
|
|
486
|
+
has_next = page < total_pages
|
|
487
|
+
has_prev = page > 1
|
|
488
|
+
|
|
489
|
+
# Calculate start and end for current page
|
|
490
|
+
start_index = (page - 1) * limit
|
|
491
|
+
end_index = min(start_index + limit, total_records)
|
|
492
|
+
|
|
493
|
+
page_start_ts = start_ts + (start_index * sample_time)
|
|
494
|
+
page_end_ts = start_ts + ((end_index - 1) * sample_time)
|
|
495
|
+
|
|
496
|
+
# Query data needed for this page plus context for forward fill
|
|
497
|
+
# We need data up to page_end_ts.
|
|
498
|
+
# For forward fill, we need the last known value before or at page_start_ts for each tag.
|
|
499
|
+
|
|
500
|
+
data_points = []
|
|
501
|
+
current_ts = page_start_ts
|
|
502
|
+
|
|
503
|
+
# Pre-fetch data for optimization could be complex due to forward fill requirement across large gaps.
|
|
504
|
+
# However, we can query per tag or query all data in range.
|
|
505
|
+
# For efficiency with many tags/large range, we should query intelligently.
|
|
506
|
+
# But to guarantee "last known value", we might need to look back indefinitely if no recent data.
|
|
507
|
+
# A simple approach for now: Query "last value before or at page_start_ts" for each tag,
|
|
508
|
+
# and all values between page_start_ts and page_end_ts.
|
|
509
|
+
|
|
510
|
+
# 1. Get initial values (state at page_start_ts)
|
|
511
|
+
current_values = {}
|
|
512
|
+
# Convert float timestamp to datetime for Peewee comparison
|
|
513
|
+
current_dt = datetime.fromtimestamp(current_ts, pytz.UTC)
|
|
514
|
+
|
|
515
|
+
for tag_name in tags:
|
|
516
|
+
# Get the latest value <= current_dt
|
|
517
|
+
last_val_query = (TagValue
|
|
518
|
+
.select(TagValue.value)
|
|
519
|
+
.join(Tags)
|
|
520
|
+
.where((Tags.name == tag_name) & (TagValue.timestamp <= current_dt))
|
|
521
|
+
.order_by(TagValue.timestamp.desc())
|
|
522
|
+
.limit(1)
|
|
523
|
+
.dicts())
|
|
524
|
+
|
|
525
|
+
entry = list(last_val_query)
|
|
526
|
+
if entry:
|
|
527
|
+
current_values[tag_name] = entry[0]['value']
|
|
528
|
+
else:
|
|
529
|
+
current_values[tag_name] = None
|
|
530
|
+
|
|
531
|
+
# 2. Get changes within the page window
|
|
532
|
+
# We query all changes for these tags in the time window of the page
|
|
533
|
+
|
|
534
|
+
# Convert boundaries to datetime for Peewee
|
|
535
|
+
page_start_dt = datetime.fromtimestamp(page_start_ts, pytz.UTC)
|
|
536
|
+
page_end_dt = datetime.fromtimestamp(page_end_ts, pytz.UTC)
|
|
537
|
+
|
|
538
|
+
changes_query = (TagValue
|
|
539
|
+
.select(Tags.name, TagValue.value, TagValue.timestamp)
|
|
540
|
+
.join(Tags)
|
|
541
|
+
.where(
|
|
542
|
+
(Tags.name.in_(tags)) &
|
|
543
|
+
(TagValue.timestamp > page_start_dt) &
|
|
544
|
+
(TagValue.timestamp <= page_end_dt) &
|
|
545
|
+
(TagValue.value.is_null(False))
|
|
546
|
+
)
|
|
547
|
+
.order_by(TagValue.timestamp.asc())
|
|
548
|
+
.dicts())
|
|
549
|
+
|
|
550
|
+
# Organize changes by timestamp
|
|
551
|
+
changes_by_ts = defaultdict(dict)
|
|
552
|
+
for change in changes_query:
|
|
553
|
+
# timestamp comes as datetime from Peewee
|
|
554
|
+
ts_val = change['timestamp']
|
|
555
|
+
if isinstance(ts_val, datetime):
|
|
556
|
+
# Ensure it's timezone aware or treat as UTC if naive
|
|
557
|
+
if ts_val.tzinfo is None:
|
|
558
|
+
ts_val = utc_timezone.localize(ts_val)
|
|
559
|
+
ts = ts_val.timestamp()
|
|
560
|
+
else:
|
|
561
|
+
ts = float(ts_val)
|
|
562
|
+
|
|
563
|
+
changes_by_ts[ts][change['name']] = change['value']
|
|
564
|
+
|
|
565
|
+
# 3. Generate tabular data
|
|
566
|
+
# We iterate step by step. This might be slow if step is small and range is large,
|
|
567
|
+
# but we are limited by pagination 'limit' (e.g. 20 rows), so it's fast!
|
|
568
|
+
|
|
569
|
+
# We need to process from page_start_ts to page_end_ts in sample_time steps.
|
|
570
|
+
# BUT we have a list of changes.
|
|
571
|
+
# The simple way: Iterate steps.
|
|
572
|
+
|
|
573
|
+
# Optimization: We have 'limit' steps.
|
|
574
|
+
|
|
575
|
+
changes_iter = sorted(changes_by_ts.keys())
|
|
576
|
+
change_idx = 0
|
|
577
|
+
|
|
578
|
+
for i in range(end_index - start_index):
|
|
579
|
+
step_ts = page_start_ts + (i * sample_time)
|
|
580
|
+
|
|
581
|
+
# Update current_values with any changes that happened between last step and now (inclusive)
|
|
582
|
+
# Actually, standard sample-hold means at time T we have value at T.
|
|
583
|
+
# If multiple values in (T-1, T], usually the last one prevails or the one at T?
|
|
584
|
+
# Requirement: "retorne exactamente el timestamp... valor anterior mas cercano registrado" (forward fill)
|
|
585
|
+
# So at step_ts, value is the latest value where timestamp <= step_ts.
|
|
586
|
+
|
|
587
|
+
# Advance change_idx to consume all changes <= step_ts
|
|
588
|
+
while change_idx < len(changes_iter) and changes_iter[change_idx] <= step_ts:
|
|
589
|
+
ts = changes_iter[change_idx]
|
|
590
|
+
for tag, val in changes_by_ts[ts].items():
|
|
591
|
+
current_values[tag] = val
|
|
592
|
+
change_idx += 1
|
|
593
|
+
|
|
594
|
+
# Build row
|
|
595
|
+
dt_object = datetime.fromtimestamp(step_ts, pytz.UTC)
|
|
596
|
+
formatted_ts = dt_object.astimezone(_timezone).strftime(DATETIME_FORMAT)
|
|
597
|
+
|
|
598
|
+
row = {"timestamp": formatted_ts}
|
|
599
|
+
has_data = False
|
|
600
|
+
for tag in tags:
|
|
601
|
+
val = current_values.get(tag)
|
|
602
|
+
row[tag] = val # None if no value ever recorded
|
|
603
|
+
if val is not None:
|
|
604
|
+
has_data = True
|
|
605
|
+
|
|
606
|
+
if has_data:
|
|
607
|
+
data_points.append(row)
|
|
608
|
+
|
|
609
|
+
return {
|
|
610
|
+
"data": data_points,
|
|
611
|
+
"pagination": {
|
|
612
|
+
"page": page,
|
|
613
|
+
"limit": limit,
|
|
614
|
+
"total_records": total_records,
|
|
615
|
+
"total_pages": total_pages,
|
|
616
|
+
"has_next": has_next,
|
|
617
|
+
"has_prev": has_prev
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
|
|
391
621
|
def _agregate_data_every_seconds(self, query, result, seconds:int, timezone:str="UTC"):
|
|
392
622
|
r"""Documentation here
|
|
393
623
|
"""
|
|
@@ -620,17 +850,18 @@ class DataLoggerEngine(BaseEngine):
|
|
|
620
850
|
_query["parameters"]["tags"] = tags
|
|
621
851
|
return self.query(_query)
|
|
622
852
|
|
|
623
|
-
def
|
|
853
|
+
def read_tabular_data(self, start:str, stop:str, timezone:str, tags:list, sample_time:int, page:int=1, limit:int=20):
|
|
624
854
|
r"""
|
|
625
|
-
Get historical data in
|
|
855
|
+
Get historical data in tabular format with pagination on a thread-safe mechanism
|
|
626
856
|
"""
|
|
627
857
|
_query = dict()
|
|
628
|
-
_query["action"] = "
|
|
858
|
+
_query["action"] = "read_tabular_data"
|
|
629
859
|
_query["parameters"] = dict()
|
|
630
860
|
_query["parameters"]["start"] = start
|
|
631
861
|
_query["parameters"]["stop"] = stop
|
|
632
862
|
_query["parameters"]["timezone"] = timezone
|
|
633
863
|
_query["parameters"]["tags"] = tags
|
|
864
|
+
_query["parameters"]["sample_time"] = sample_time
|
|
634
865
|
_query["parameters"]["page"] = page
|
|
635
866
|
_query["parameters"]["limit"] = limit
|
|
636
867
|
return self.query(_query)
|
|
@@ -68,7 +68,9 @@ class EventsLogger(BaseLogger):
|
|
|
68
68
|
classification:str="",
|
|
69
69
|
greater_than_timestamp:datetime=None,
|
|
70
70
|
less_than_timestamp:datetime=None,
|
|
71
|
-
timezone:str="UTC"
|
|
71
|
+
timezone:str="UTC",
|
|
72
|
+
page:int=1,
|
|
73
|
+
limit:int=20
|
|
72
74
|
):
|
|
73
75
|
r"""
|
|
74
76
|
Documentation here
|
|
@@ -90,7 +92,9 @@ class EventsLogger(BaseLogger):
|
|
|
90
92
|
description=description,
|
|
91
93
|
greater_than_timestamp=greater_than_timestamp,
|
|
92
94
|
less_than_timestamp=less_than_timestamp,
|
|
93
|
-
timezone=timezone
|
|
95
|
+
timezone=timezone,
|
|
96
|
+
page=page,
|
|
97
|
+
limit=limit
|
|
94
98
|
)
|
|
95
99
|
|
|
96
100
|
def get_summary(self)->tuple[list, str]:
|
|
@@ -164,7 +168,9 @@ class EventsLoggerEngine(BaseEngine):
|
|
|
164
168
|
description:str="",
|
|
165
169
|
greater_than_timestamp:datetime=None,
|
|
166
170
|
less_than_timestamp:datetime=None,
|
|
167
|
-
timezone:str='UTC'
|
|
171
|
+
timezone:str='UTC',
|
|
172
|
+
page:int=1,
|
|
173
|
+
limit:int=20
|
|
168
174
|
):
|
|
169
175
|
|
|
170
176
|
_query = dict()
|
|
@@ -179,6 +185,8 @@ class EventsLoggerEngine(BaseEngine):
|
|
|
179
185
|
_query["parameters"]["greater_than_timestamp"] = greater_than_timestamp
|
|
180
186
|
_query["parameters"]["less_than_timestamp"] = less_than_timestamp
|
|
181
187
|
_query["parameters"]["timezone"] = timezone
|
|
188
|
+
_query["parameters"]["page"] = page
|
|
189
|
+
_query["parameters"]["limit"] = limit
|
|
182
190
|
|
|
183
191
|
return self.query(_query)
|
|
184
192
|
|
{pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/modules/alarms/resources/summary.py
RENAMED
|
@@ -16,7 +16,9 @@ alarms_summary_filter_model = api.model("alarms_summary_filter_model",{
|
|
|
16
16
|
'tags': fields.List(fields.String(), required=False),
|
|
17
17
|
'greater_than_timestamp': fields.DateTime(required=False, default=datetime.now(pytz.utc).astimezone(TIMEZONE) - timedelta(minutes=30), description=f'Greater than timestamp - DateTime Format: {app.cvt.DATETIME_FORMAT}'),
|
|
18
18
|
'less_than_timestamp': fields.DateTime(required=False, default=datetime.now(pytz.utc).astimezone(TIMEZONE), description=f'Less than timestamp - DateTime Format: {app.cvt.DATETIME_FORMAT}'),
|
|
19
|
-
'timezone': fields.String(required=False, default=_TIMEZONE)
|
|
19
|
+
'timezone': fields.String(required=False, default=_TIMEZONE),
|
|
20
|
+
'page': fields.Integer(required=False, default=1, description='Page number'),
|
|
21
|
+
'limit': fields.Integer(required=False, default=20, description='Items per page')
|
|
20
22
|
})
|
|
21
23
|
|
|
22
24
|
|
|
@@ -20,7 +20,9 @@ events_filter_model = api.model("events_filter_model",{
|
|
|
20
20
|
'description': fields.String(required=False),
|
|
21
21
|
'greater_than_timestamp': fields.DateTime(required=False, default=datetime.now(pytz.utc).astimezone(TIMEZONE) - timedelta(minutes=30), description=f'Greater than timestamp - DateTime Format: {app.cvt.DATETIME_FORMAT}'),
|
|
22
22
|
'less_than_timestamp': fields.DateTime(required=False, default=datetime.now(pytz.utc).astimezone(TIMEZONE), description=f'Less than timestamp - DateTime Format: {app.cvt.DATETIME_FORMAT}'),
|
|
23
|
-
'timezone': fields.String(required=False, default=_TIMEZONE)
|
|
23
|
+
'timezone': fields.String(required=False, default=_TIMEZONE),
|
|
24
|
+
'page': fields.Integer(required=False, default=1, description='Page number'),
|
|
25
|
+
'limit': fields.Integer(required=False, default=20, description='Items per page')
|
|
24
26
|
})
|
|
25
27
|
|
|
26
28
|
|
|
@@ -25,6 +25,16 @@ query_table_model = api.model("query_table_model",{
|
|
|
25
25
|
'limit': fields.Integer(required=False, default=20, description='Items per page')
|
|
26
26
|
})
|
|
27
27
|
|
|
28
|
+
query_tabular_data_model = api.model("query_tabular_data_model",{
|
|
29
|
+
'tags': fields.List(fields.String(), required=True),
|
|
30
|
+
'greater_than_timestamp': fields.DateTime(required=True, default=datetime.now(pytz.utc).astimezone(TIMEZONE) - timedelta(minutes=30), description='Greater than DateTime'),
|
|
31
|
+
'less_than_timestamp': fields.DateTime(required=True, default=datetime.now(pytz.utc).astimezone(TIMEZONE), description='Less than DateTime'),
|
|
32
|
+
'sample_time': fields.Integer(required=True, description='Sample time in seconds'),
|
|
33
|
+
'timezone': fields.String(required=True, default=_TIMEZONE),
|
|
34
|
+
'page': fields.Integer(required=False, default=1, description='Page number'),
|
|
35
|
+
'limit': fields.Integer(required=False, default=20, description='Items per page')
|
|
36
|
+
})
|
|
37
|
+
|
|
28
38
|
write_value_model = api.model("write_value_model", {
|
|
29
39
|
'tag_name': fields.String(required=True, description='Nombre del tag'),
|
|
30
40
|
'value': fields.Raw(required=True, description='Valor a escribir (float, int, bool, str)')
|
|
@@ -134,6 +144,49 @@ class QueryTableResource(Resource):
|
|
|
134
144
|
|
|
135
145
|
return result, 200
|
|
136
146
|
|
|
147
|
+
@ns.route('/get_tabular_data')
|
|
148
|
+
class GetTabularDataResource(Resource):
|
|
149
|
+
|
|
150
|
+
@api.doc(security='apikey')
|
|
151
|
+
@Api.token_required(auth=True)
|
|
152
|
+
@ns.expect(query_tabular_data_model)
|
|
153
|
+
def post(self):
|
|
154
|
+
"""
|
|
155
|
+
Query tag values in tabular format with pagination and resampling.
|
|
156
|
+
|
|
157
|
+
The result contains data points at regular intervals (sample_time) from greater_than_timestamp
|
|
158
|
+
up to less_than_timestamp. If exact data is missing, the previous known value is used (forward fill).
|
|
159
|
+
|
|
160
|
+
Authorized Roles: {0}
|
|
161
|
+
"""
|
|
162
|
+
timezone = _TIMEZONE
|
|
163
|
+
tags = api.payload['tags']
|
|
164
|
+
page = api.payload.get('page', 1)
|
|
165
|
+
limit = api.payload.get('limit', 20)
|
|
166
|
+
sample_time = api.payload.get('sample_time', 60) # Default 1 min if not provided, but model requires it
|
|
167
|
+
|
|
168
|
+
if "timezone" in api.payload:
|
|
169
|
+
timezone = api.payload["timezone"]
|
|
170
|
+
|
|
171
|
+
if timezone not in pytz.all_timezones:
|
|
172
|
+
return f"Invalid Timezone", 400
|
|
173
|
+
|
|
174
|
+
for tag in tags:
|
|
175
|
+
if not app.get_tag_by_name(name=tag):
|
|
176
|
+
return f"{tag} not exist into db", 404
|
|
177
|
+
|
|
178
|
+
separator = '.'
|
|
179
|
+
greater_than_timestamp = api.payload['greater_than_timestamp']
|
|
180
|
+
# Ensure timestamp format is consistent
|
|
181
|
+
start = greater_than_timestamp.replace("T", " ").split(separator, 1)[0] + '.00'
|
|
182
|
+
|
|
183
|
+
less_than_timestamp = api.payload['less_than_timestamp']
|
|
184
|
+
stop = less_than_timestamp.replace("T", " ").split(separator, 1)[0] + '.00'
|
|
185
|
+
|
|
186
|
+
result = app.get_tabular_data(start, stop, timezone, tags, sample_time, page, limit)
|
|
187
|
+
|
|
188
|
+
return result, 200
|
|
189
|
+
|
|
137
190
|
@ns.route('/write_value')
|
|
138
191
|
class WriteValueResource(Resource):
|
|
139
192
|
|
|
@@ -457,6 +457,8 @@ class StateMachineCore(StateMachine):
|
|
|
457
457
|
self.transitions = transitions
|
|
458
458
|
self.manufacturer = MANUFACTURER
|
|
459
459
|
self.segment = SEGMENT
|
|
460
|
+
self.mass_flow_unit_base = "kg/sec"
|
|
461
|
+
self.volumetric_flow_unit_base = "m3/sec"
|
|
460
462
|
super(StateMachineCore, self).__init__()
|
|
461
463
|
|
|
462
464
|
# State Methods
|
pyautomationio-1.0.3/version.py
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/modules/alarms/resources/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/modules/events/resources/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/modules/users/resources/__init__.py
RENAMED
|
File without changes
|
{pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/modules/users/resources/models/__init__.py
RENAMED
|
File without changes
|
{pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/modules/users/resources/models/roles.py
RENAMED
|
File without changes
|
{pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/modules/users/resources/models/users.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/callbacks/machines_detailed.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyautomationio-1.0.3 → pyautomationio-1.1.1}/automation/pages/components/gaussian_filter.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|