forked from zietzm/Helmholtz_Test_Bench
Initial Upload
This commit is contained in:
+96
@@ -0,0 +1,96 @@
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
env/
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*,cover
|
||||
.hypothesis/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# IPython Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# celery beat schedule file
|
||||
celerybeat-schedule
|
||||
|
||||
# dotenv
|
||||
.env
|
||||
|
||||
# virtualenv
|
||||
.venv/
|
||||
venv/
|
||||
ENV/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# PyCharm
|
||||
.idea
|
||||
|
||||
# VScode
|
||||
.vscode/
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016 Sören Sprößig
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,2 +1,68 @@
|
||||
# Magnetfeldteststand
|
||||
# Python-PS2000B
|
||||
Python library to work with Elektro-Automatik PS 2000 B power supplies via USB.
|
||||
|
||||
## Compatibility
|
||||
Tested with:
|
||||
|
||||
+ Python 2.7
|
||||
+ Python 3.5, 3.6
|
||||
|
||||
Tested on:
|
||||
|
||||
+ Windows 7 x64
|
||||
+ Windows 10 x64 Version 1607 (OS Build 14393.2035)
|
||||
+ Ubuntu 16.04.1 LTS
|
||||
+ Ubuntu 20.04.1 LTS
|
||||
|
||||
## Features of Python-PS2000B
|
||||
### Supported
|
||||
- read static device information (manufacturer, serial, device type ...)
|
||||
- read dynamic device information (current, voltage)
|
||||
- read/write remote control
|
||||
- read/write output control
|
||||
|
||||
### Still todo
|
||||
- set voltage and current
|
||||
- wrap error results in own telegram
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Python
|
||||
The following third-party Python libraries are needed:
|
||||
|
||||
* `pyserial` - serial communication library for Python, see https://pypi.python.org/pypi/pyserial
|
||||
|
||||
### Windows
|
||||
On Windows the USB driver (fetch it from http://www.elektroautomatik.de/files/eautomatik/treiber/usb/ea_device_driver.rar) must be installed. Afterwards you can find the serial port `COMxx` in the *device manager*.
|
||||
|
||||
### Linux
|
||||
On Linux the device is detected as `/dev/ttyACMx` (abstract control model, see https://www.rfc1149.net/blog/2013/03/05/what-is-the-difference-between-devttyusbx-and-devttyacmx/). Use `dmesg` after connecting the device to find out `x`.
|
||||
|
||||
Most Linuxes will require users to elevate for accessing the device. If you want to access the device as your current user, just add it to the group `dialout` (`ls -lah /dev/ttyACM0` will show you the group to use, usually this is `dialout`) and login again.
|
||||
|
||||
## Usage
|
||||
```python
|
||||
import time
|
||||
from pyps2000b import PS2000B
|
||||
|
||||
|
||||
device = PS2000B.PS2000B("/dev/ttyACM0")
|
||||
|
||||
print("Device status: %s" % device.get_device_status_information())
|
||||
|
||||
device.enable_remote_control()
|
||||
device.voltage1 = 5.1
|
||||
device.current1 = 1
|
||||
device.enable_output()
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
print("Current output: %0.2f V , %0.2f A" % (device.get_voltage(), device.get_current()))
|
||||
|
||||
device.output1 = False
|
||||
```
|
||||
|
||||
## Documentation
|
||||
+ product website: http://www.elektroautomatik.de/en/ps2000b.html
|
||||
+ programming guide PS 2000 B: http://www.elektroautomatik.de/files/eautomatik/treiber/ps2000b/programming_ps2000b.zip
|
||||
|
||||
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env python3
|
||||
# coding=utf-8
|
||||
import platform
|
||||
import time
|
||||
|
||||
from pyps2000b import PS2000B
|
||||
|
||||
|
||||
DEVICE = "COM7" if platform.system() == "Windows" else "/dev/ttyACM0"
|
||||
|
||||
# connection to the device is automatically opened
|
||||
print("Connecting to device at %s..." % DEVICE)
|
||||
device1 = PS2000B.PS2000B(DEVICE) # create Object of class PS2000B, pass COM-port and channel to functions inside
|
||||
|
||||
# static device information can be read
|
||||
print("Connection open: %s" % device1.is_open())
|
||||
print("Device: %s" % device1.get_device_information())
|
||||
|
||||
# dynamic device status information can be read
|
||||
device_status_info1 = device1.get_device_status_information(0)
|
||||
device_status_info2 = device1.get_device_status_information(1)
|
||||
print("Device status 1: %s" % device1.get_device_status_information(0))
|
||||
print("Device status 2: %s" % device1.get_device_status_information(1))
|
||||
print("Current output 1: %0.2f V , %0.2f A" % (device1.voltage1, device1.current1))
|
||||
print("Current output 2: %0.2f V , %0.2f A" % (device1.voltage2, device1.current2))
|
||||
|
||||
# device can be controlled
|
||||
if not device_status_info1.remote_control_active:
|
||||
print("...will enable remote control...")
|
||||
device1.enable_remote_control(0)
|
||||
if not device_status_info2.remote_control_active:
|
||||
print("...will enable remote control...")
|
||||
device1.enable_remote_control(1)
|
||||
|
||||
print("...set voltage 1 to 12V and max current to 1A...")
|
||||
device1.voltage1 = 12
|
||||
device1.current1 = 1
|
||||
time.sleep(2)
|
||||
print("...now enabling the power output control 1...")
|
||||
device1.enable_output(0)
|
||||
|
||||
time.sleep(2)
|
||||
print("... set voltage 2 to 5V and max current to 1A...")
|
||||
device1.voltage2 = 5
|
||||
device1.current2 = 1
|
||||
time.sleep(2)
|
||||
print("...now enabling the power output control 2...")
|
||||
device1.enable_output(1)
|
||||
|
||||
time.sleep(5)
|
||||
print("Device status 1: %s" % device1.get_device_status_information(0))
|
||||
print("Device status 2: %s" % device1.get_device_status_information(1))
|
||||
print("Current output 1: %0.2f V , %0.2f A" % (device1.voltage1, device1.current1))
|
||||
print("Current output 2: %0.2f V , %0.2f A" % (device1.voltage2, device1.current2))
|
||||
|
||||
time.sleep(5)
|
||||
device1.disable_output(0)
|
||||
device1.disable_output(1)
|
||||
print("...and disabling remote control again.")
|
||||
device1.disable_remote_control(0)
|
||||
device1.disable_remote_control(1)
|
||||
|
||||
print("Device status 1: %s" % device1.get_device_status_information(0))
|
||||
print("Device status 2: %s" % device1.get_device_status_information(1))
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env python3
|
||||
# coding=utf-8
|
||||
import platform
|
||||
import time
|
||||
|
||||
from pyps2000b import PS2000B
|
||||
|
||||
|
||||
DEVICE = "COM7" if platform.system() == "Windows" else "/dev/ttyACM0"
|
||||
|
||||
# connection to the device is automatically opened
|
||||
print("Connecting to device at %s..." % DEVICE)
|
||||
device = PS2000B.PS2000B(DEVICE) # create Object of class PS2000B, pass COM-port to functions inside
|
||||
|
||||
# static device information can be read
|
||||
print("Connection open: %s" % device.is_open())
|
||||
print("Device: %s" % device.get_device_information())
|
||||
|
||||
# dynamic device status information can be read
|
||||
device_status_info1 = device.get_device_status_information(0)
|
||||
device_status_info2 = device.get_device_status_information(1)
|
||||
print("Device status 1: %s" % device_status_info1)
|
||||
print("Device status 2: %s" % device_status_info2)
|
||||
|
||||
print("Current output: %0.2f V , %0.2f A" % (device.get_voltage(), device.get_current()))
|
||||
|
||||
# device can be controlled
|
||||
if not device_status_info.remote_control_active:
|
||||
print("...will enable remote control...")
|
||||
device.enable_remote_control()
|
||||
|
||||
print("...set voltage to 12V and max current to 1A...")
|
||||
device.voltage1 = 12
|
||||
device.current1 = 1
|
||||
time.sleep(10)
|
||||
print("...now enabling the power output control...")
|
||||
device.enable_output()
|
||||
time.sleep(2)
|
||||
device_status_info1 = device.get_device_status_information(0)
|
||||
device_status_info2 = device.get_device_status_information(1)
|
||||
print("Device status 1: %s" % device_status_info1)
|
||||
print("Device status 2: %s" % device_status_info2)
|
||||
print("Current output: %0.2f V , %0.2f A" % (device.voltage1, device.current1))
|
||||
time.sleep(10)
|
||||
print("...set voltage to 5.1V...")
|
||||
device.voltage1 = 5.1
|
||||
time.sleep(10)
|
||||
print("Current output: %0.2f V , %0.2f A" % (device.get_voltage(), device.get_current()))
|
||||
print("...after 5 seconds power output will be disabled again ...")
|
||||
time.sleep(5)
|
||||
device.disable_output()
|
||||
print("...and disabling remote control again.")
|
||||
device.disable_remote_control()
|
||||
|
||||
print("Device status 1: %s" % device.get_device_status_information(0))
|
||||
print("Device status 2: %s" % device.get_device_status_information(1))
|
||||
@@ -0,0 +1,382 @@
|
||||
#!/usr/bin/env python3
|
||||
# coding=utf-8
|
||||
# Python access to Elektro Automatik PS 2000 B devices via USB/serial
|
||||
#
|
||||
# Supported features:
|
||||
# - read static device information (manufacturer, serial, device type ...)
|
||||
# - read dynamic device information (current, voltage)
|
||||
# - read/write remote control
|
||||
# - read/write output control
|
||||
#
|
||||
# Todo:
|
||||
# - wrap error results in own telegram
|
||||
#
|
||||
# References
|
||||
# [1] = "PS 2000B Programming Guide" from 2015-05-28
|
||||
# [2] = "PS 2000B object list"
|
||||
#
|
||||
|
||||
import serial
|
||||
import struct
|
||||
import sys
|
||||
PY_3 = sys.version_info >= (3, 0)
|
||||
|
||||
|
||||
__author__ = "Sören Sprößig <ssproessig@gmail.com>"
|
||||
|
||||
|
||||
def as_string(raw_data):
|
||||
"""Converts the given raw bytes to a string (removes NULL)"""
|
||||
return bytearray(raw_data[:-1])
|
||||
|
||||
|
||||
def as_float(raw_data):
|
||||
"""Converts the given raw bytes to a float"""
|
||||
f = struct.unpack_from(">f", bytearray(raw_data))[0]
|
||||
return f
|
||||
|
||||
|
||||
def as_word(raw_data):
|
||||
"""Converts the given raw bytes to a word"""
|
||||
w = struct.unpack_from(">H", bytearray(raw_data))[0]
|
||||
return w
|
||||
|
||||
|
||||
def _ord(x):
|
||||
"""Wrap ord() call as we only need it in Python 2"""
|
||||
return x if PY_3 else ord(x)
|
||||
|
||||
|
||||
# noinspection PyClassHasNoInit
|
||||
class Constants:
|
||||
"""Communication constants"""
|
||||
# communication parameters taken from [1], chapter 2.2
|
||||
CONNECTION_BAUD_RATE = 115200
|
||||
CONNECTION_PARITY = serial.PARITY_ODD
|
||||
CONNECTION_STOP_BITS = 1
|
||||
# timeout taken from [1], chapter 3.7
|
||||
TIMEOUT_BETWEEN_COMMANDS = 0.05
|
||||
# according to spec [1] 2.4:
|
||||
# maximum length of a telegram is 21 bytes (Byte 0..20)
|
||||
MAX_LEN_IN_BYTES = 21
|
||||
|
||||
|
||||
# noinspection PyClassHasNoInit
|
||||
class Objects:
|
||||
"""Supported objects ids / commands"""
|
||||
DEVICE_TYPE = 0
|
||||
DEVICE_SERIAL_NO = 1
|
||||
NOMINAL_VOLTAGE = 2
|
||||
NOMINAL_CURRENT = 3
|
||||
NOMINAL_POWER = 4
|
||||
DEVICE_ARTICLE_NO = 6
|
||||
MANUFACTURER = 8
|
||||
SOFTWARE_VERSION = 9
|
||||
SET_VALUE_VOLTAGE = 50
|
||||
SET_VALUE_CURRENT = 51
|
||||
POWER_SUPPLY_CONTROL = 54
|
||||
STATUS_ACTUAL_VALUES = 71
|
||||
|
||||
|
||||
# noinspection PyClassHasNoInit
|
||||
class ControlParameters:
|
||||
"""Parameters for controlling the device"""
|
||||
SWITCH_MODE_CMD = 0x10
|
||||
SWITCH_MODE_REMOTE = 0x10
|
||||
SWITCH_MODE_MANUAL = 0x00
|
||||
SWITCH_POWER_OUTPUT_CMD = 0x1
|
||||
SWITCH_POWER_OUTPUT_ON = 0x1
|
||||
SWITCH_POWER_OUTPUT_OFF = 0x0
|
||||
|
||||
|
||||
class Telegram:
|
||||
"""Base class of a PS2000B telegram - basically allows accessing the raw bytes and does checksum calculation"""
|
||||
|
||||
def __init__(self):
|
||||
self._bytes = []
|
||||
self._checksum = []
|
||||
self.checksum_ok = False
|
||||
|
||||
def _calc_checksum(self):
|
||||
cs = 0
|
||||
|
||||
for b in self._bytes:
|
||||
cs += b
|
||||
|
||||
cs_high = (cs & 0xff00) >> 8
|
||||
cs_low = cs & 0xff
|
||||
|
||||
return [cs_high, cs_low]
|
||||
|
||||
@staticmethod
|
||||
def _get_start_delimiter(transmission, expected_data_length):
|
||||
result = 0b00000000
|
||||
|
||||
if expected_data_length > 16:
|
||||
raise Exception("only 4 bits for expected length can be used")
|
||||
|
||||
result |= (expected_data_length - 1)
|
||||
result |= 0b10000
|
||||
result |= 0b100000
|
||||
result |= transmission << 6
|
||||
return result
|
||||
|
||||
def get_byte_array(self):
|
||||
return bytearray(self._bytes + self._checksum)
|
||||
|
||||
|
||||
class FromPowerSupply(Telegram):
|
||||
"""Telegram received from the power supply"""
|
||||
|
||||
def __init__(self, raw_data):
|
||||
Telegram.__init__(self)
|
||||
data = [_ord(x) for x in raw_data]
|
||||
self._bytes = data[0:-2]
|
||||
self._checksum = data[len(data) - 2:len(data)]
|
||||
self.checksum_ok = self._checksum == self._calc_checksum()
|
||||
|
||||
def get_sd(self):
|
||||
return self._bytes[0]
|
||||
|
||||
def get_device_node(self):
|
||||
return self._bytes[1]
|
||||
|
||||
def get_object(self):
|
||||
return self._bytes[3]
|
||||
|
||||
def get_data(self):
|
||||
return self._bytes[3:len(self._bytes)]
|
||||
|
||||
# noinspection PyMethodMayBeStatic
|
||||
def get_error(self):
|
||||
# FIXME: [1] chapter 3.6 add support for error codes here
|
||||
return None
|
||||
|
||||
|
||||
class ToPowerSupply(Telegram):
|
||||
"""A telegram sent to the power supply"""
|
||||
|
||||
def __init__(self, transmission, data, expected_data_length):
|
||||
Telegram.__init__(self)
|
||||
self._bytes = []
|
||||
self._bytes.append(self._get_start_delimiter(transmission, expected_data_length))
|
||||
self._bytes.extend(data)
|
||||
self._checksum = self._calc_checksum()
|
||||
self.checksum_ok = True
|
||||
|
||||
|
||||
class DeviceInformation:
|
||||
"""A class carrying all static device information read from the device"""
|
||||
|
||||
def __init__(self):
|
||||
self.device_type = ""
|
||||
self.device_serial_no = ""
|
||||
self.nominal_voltage = 0
|
||||
self.nominal_current = 0
|
||||
self.nominal_power = 0
|
||||
self.manufacturer = ""
|
||||
self.device_article_number = ""
|
||||
self.software_version = ""
|
||||
|
||||
def __str__(self):
|
||||
return "%s %s [%s], SW: %s, Art-Nr: %s, [%0.2f V, %0.2f A, %0.2f W]" % \
|
||||
(self.manufacturer,
|
||||
self.device_type, self.device_serial_no,
|
||||
self.software_version, self.device_article_number,
|
||||
self.nominal_voltage, self.nominal_current, self.nominal_power)
|
||||
|
||||
|
||||
class DeviceStatusInformation:
|
||||
"""A class carrying all dynamic device status information"""
|
||||
|
||||
def __init__(self, raw_data):
|
||||
self.remote_control_active = raw_data[0] & 0b1
|
||||
self.output_active = raw_data[1] & 0b1
|
||||
self.actual_voltage_percent = float(as_word(raw_data[2:4])) / 256
|
||||
self.actual_current_percent = float(as_word(raw_data[4:6])) / 256
|
||||
|
||||
def __str__(self):
|
||||
return "Remote control active: %s, Output active: %s" % (self.remote_control_active, self.output_active)
|
||||
|
||||
|
||||
class PS2000B:
|
||||
"""PS 2000 B main communication class"""
|
||||
|
||||
def __init__(self, serial_port):
|
||||
self.__device_status_information1 = None
|
||||
self.__device_status_information2 = None
|
||||
self.__serial = serial.Serial(serial_port,
|
||||
baudrate=Constants.CONNECTION_BAUD_RATE,
|
||||
timeout=Constants.TIMEOUT_BETWEEN_COMMANDS * 2,
|
||||
parity=serial.PARITY_ODD,
|
||||
stopbits=Constants.CONNECTION_STOP_BITS)
|
||||
|
||||
self.__device_information = self.__read_device_information()
|
||||
|
||||
def is_open(self):
|
||||
return self.__serial.is_open
|
||||
|
||||
def get_device_information(self):
|
||||
return self.__device_information
|
||||
|
||||
def __read_device_information(self, channel=0):
|
||||
result = DeviceInformation()
|
||||
|
||||
# taken from [2]
|
||||
result.device_type = as_string(self.__read_device_data(16, Objects.DEVICE_TYPE, channel).get_data())
|
||||
result.device_serial_no = as_string(self.__read_device_data(16, Objects.DEVICE_SERIAL_NO, channel).get_data())
|
||||
result.nominal_voltage = as_float(self.__read_device_data(4, Objects.NOMINAL_VOLTAGE, channel).get_data())
|
||||
result.nominal_current = as_float(self.__read_device_data(4, Objects.NOMINAL_CURRENT, channel).get_data())
|
||||
result.nominal_power = as_float(self.__read_device_data(4, Objects.NOMINAL_POWER, channel).get_data())
|
||||
result.device_article_number = as_string(self.__read_device_data(16, Objects.DEVICE_ARTICLE_NO, channel).get_data())
|
||||
result.manufacturer = as_string(self.__read_device_data(16, Objects.MANUFACTURER, channel).get_data())
|
||||
result.software_version = as_string(self.__read_device_data(16, Objects.SOFTWARE_VERSION, channel).get_data())
|
||||
|
||||
return result
|
||||
|
||||
def __read_device_data(self, expected_length, object_id, channel):
|
||||
telegram = ToPowerSupply(0b01, [channel, object_id], expected_length)
|
||||
result = self.__send_and_receive(telegram.get_byte_array())
|
||||
return result
|
||||
|
||||
def __send_and_receive(self, raw_bytes):
|
||||
self.__serial.write(raw_bytes)
|
||||
result = FromPowerSupply(self.__serial.read(Constants.MAX_LEN_IN_BYTES))
|
||||
return result
|
||||
|
||||
def get_device_status_information(self, channel=0):
|
||||
""":returns DeviceStatusInformation"""
|
||||
if channel == 0:
|
||||
if self.__device_status_information1 is None:
|
||||
self.update_device_information(0)
|
||||
info = self.__device_status_information1
|
||||
elif channel == 1:
|
||||
if self.__device_status_information2 is None:
|
||||
self.update_device_information(1)
|
||||
info = self.__device_status_information2
|
||||
else:
|
||||
info = None
|
||||
raise ValueError("Invalid Channel")
|
||||
return info
|
||||
|
||||
def update_device_information(self, channel=0):
|
||||
telegram = ToPowerSupply(0b01, [channel, Objects.STATUS_ACTUAL_VALUES], 6)
|
||||
device_information = self.__send_and_receive(telegram.get_byte_array())
|
||||
if channel == 0:
|
||||
self.__device_status_information1 = DeviceStatusInformation(device_information.get_data())
|
||||
elif channel == 1:
|
||||
self.__device_status_information2 = DeviceStatusInformation(device_information.get_data())
|
||||
else:
|
||||
raise ValueError("Invalid Channel")
|
||||
|
||||
def __send_device_control(self, p1, p2, channel=0):
|
||||
telegram = ToPowerSupply(0b11, [channel, Objects.POWER_SUPPLY_CONTROL, p1, p2], 2)
|
||||
_ = self.__send_and_receive(telegram.get_byte_array())
|
||||
self.update_device_information(channel)
|
||||
|
||||
def __send_device_data(self, obj, data, channel):
|
||||
'''
|
||||
Send integer data with obj-id to the PSU
|
||||
'''
|
||||
telegram = ToPowerSupply(0b11, [channel, obj, data >> 8, data & 0xff], 4)
|
||||
_ = self.__send_and_receive(telegram.get_byte_array())
|
||||
self.update_device_information(channel)
|
||||
|
||||
def enable_remote_control(self, channel):
|
||||
self.__send_device_control(ControlParameters.SWITCH_MODE_CMD, ControlParameters.SWITCH_MODE_REMOTE, channel)
|
||||
|
||||
def disable_remote_control(self, channel):
|
||||
self.__send_device_control(ControlParameters.SWITCH_MODE_CMD, ControlParameters.SWITCH_MODE_MANUAL, channel)
|
||||
|
||||
def enable_output(self, channel):
|
||||
self.__send_device_control(ControlParameters.SWITCH_POWER_OUTPUT_CMD, ControlParameters.SWITCH_POWER_OUTPUT_ON, channel)
|
||||
|
||||
def disable_output(self, channel):
|
||||
self.__send_device_control(ControlParameters.SWITCH_POWER_OUTPUT_CMD, ControlParameters.SWITCH_POWER_OUTPUT_OFF, channel)
|
||||
|
||||
@property
|
||||
def output1(self,):
|
||||
return self.get_device_status_information(0).output_active
|
||||
|
||||
@output1.setter
|
||||
def output1(self, value):
|
||||
if value:
|
||||
self.enable_output()
|
||||
else:
|
||||
self.disable_output()
|
||||
|
||||
def get_voltage(self, channel=0):
|
||||
self.update_device_information(channel)
|
||||
if channel == 0:
|
||||
v_perc = self.__device_status_information1.actual_voltage_percent
|
||||
elif channel == 1:
|
||||
v_perc = self.__device_status_information2.actual_voltage_percent
|
||||
else:
|
||||
raise ValueError("Invalid channel")
|
||||
voltage = self.__device_information.nominal_voltage * v_perc
|
||||
return voltage / 100
|
||||
|
||||
def get_voltage_setpoint(self, channel=0):
|
||||
res = self.__read_device_data(2, Objects.SET_VALUE_VOLTAGE, channel).get_data()
|
||||
return self.__device_information.nominal_voltage * ((res[0]<<8) + res[1]) / 25600.0
|
||||
|
||||
def set_voltage(self, value, channel):
|
||||
self.update_device_information(channel)
|
||||
self.enable_remote_control(channel)
|
||||
volt = int(round( (value * 25600.0) / self.__device_information.nominal_voltage ))
|
||||
self.__send_device_data(Objects.SET_VALUE_VOLTAGE, volt, channel)
|
||||
#self.disable_remote_control()
|
||||
|
||||
@property
|
||||
def voltage1(self):
|
||||
return self.get_voltage(0)
|
||||
|
||||
@voltage1.setter
|
||||
def voltage1(self, value): # voltage of channel 1
|
||||
self.set_voltage(value, 0)
|
||||
|
||||
@property
|
||||
def voltage2(self):
|
||||
return self.get_voltage(1)
|
||||
|
||||
@voltage2.setter
|
||||
def voltage2(self, value): # voltage of channel 2
|
||||
self.set_voltage(value, 1)
|
||||
|
||||
def get_current(self, channel=0):
|
||||
self.update_device_information(channel)
|
||||
if channel == 0:
|
||||
c_perc = self.__device_status_information1.actual_current_percent
|
||||
elif channel == 1:
|
||||
c_perc = self.__device_status_information2.actual_current_percent
|
||||
else:
|
||||
raise ValueError("Invalid channel")
|
||||
current = self.__device_information.nominal_current * c_perc
|
||||
return current / 100
|
||||
|
||||
def get_current_setpoint(self, channel=0):
|
||||
res = self.__read_device_data(2, Objects.SET_VALUE_CURRENT, channel).get_data()
|
||||
return self.__device_information.nominal_current * ((res[0] << 8) + res[1]) / 25600.0
|
||||
|
||||
def set_current(self, value, channel):
|
||||
self.update_device_information(channel)
|
||||
self.enable_remote_control(channel)
|
||||
curr = int(round( (value * 25600.0) / self.__device_information.nominal_current))
|
||||
self.__send_device_data(Objects.SET_VALUE_CURRENT, curr, channel)
|
||||
# self.disable_remote_control()
|
||||
|
||||
@property
|
||||
def current1(self):
|
||||
return self.get_current(0)
|
||||
|
||||
@current1.setter
|
||||
def current1(self, value): # current of channel 1
|
||||
self.set_current(value, 0)
|
||||
|
||||
@property
|
||||
def current2(self):
|
||||
return self.get_current(1)
|
||||
|
||||
@current2.setter
|
||||
def current2(self, value): # current of channel 2
|
||||
self.set_current(value, 1)
|
||||
@@ -0,0 +1,3 @@
|
||||
#!/usr/bin/python
|
||||
# coding=utf-8
|
||||
__author__ = "Sören Sprößig <ssproessig@gmail.com>"
|
||||
Reference in New Issue
Block a user