--- /dev/null
+# Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http:#www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Internal use only.
+
+This file provide method to control programmable attenuator.
+"""
+
+import time
+import serial
+
+
+def set_att(port, att, att_fix=False):
+ """
+ set attenuation value on the attenuator
+
+ :param port: serial port for attenuator
+ :param att: attenuation value we want to set
+ :param att_fix: fix the deviation with experience value
+ :return: True or False
+ """
+
+ assert 0 <= att <= 62
+ # fix att
+ if att_fix:
+ if att >= 33 and (att - 30 + 1) % 4 == 0:
+ att_t = att - 1
+ elif att >= 33 and (att - 30) % 4 == 0:
+ att_t = att + 1
+ else:
+ att_t = att
+ else:
+ att_t = att
+
+ serial_port = serial.Serial(port, baudrate=9600, rtscts=False, timeout=0.1)
+ if serial_port.isOpen() is False:
+ raise IOError("attenuator control, failed to open att port")
+
+ cmd_hex = "7e7e10{:02x}{:x}".format(att_t, 0x10 + att_t)
+ exp_res_hex = "7e7e20{:02x}00{:x}".format(att_t, 0x20 + att_t)
+
+ cmd = cmd_hex.decode("hex")
+ exp_res = exp_res_hex.decode("hex")
+
+ serial_port.write(cmd)
+ res = ""
+
+ for i in range(5):
+ res += serial_port.read(20)
+ if res == exp_res:
+ result = True
+ break
+ time.sleep(0.1)
+ else:
+ result = False
+
+ serial_port.close()
+ return result
--- /dev/null
+# Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http:#www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import matplotlib
+# fix can't draw figure with docker
+matplotlib.use('Agg')
+import matplotlib.pyplot as plt
+
+
+# candidate colors
+LINE_STYLE_CANDIDATE = ['b-o', 'r-o', 'k-o', 'm-o', 'c-o', 'g-o', 'y-o',
+ 'b-s', 'r-s', 'k-s', 'm-s', 'c-s', 'g-s', 'y-s']
+
+
+def draw_line_chart(file_name, title, x_label, y_label, data_list):
+ """
+ draw line chart and save to file.
+
+ :param file_name: abs/relative file name to save chart figure
+ :param title: chart title
+ :param x_label: x-axis label
+ :param y_label: y-axis label
+ :param data_list: a list of line data.
+ each line is a dict of ("x-axis": list, "y-axis": list, "label": string)
+ """
+
+ plt.figure(figsize=(12, 6))
+ plt.grid(True)
+
+ for i, data in enumerate(data_list):
+ plt.plot(data["x-axis"], data["y-axis"], LINE_STYLE_CANDIDATE[i], label=data["label"])
+
+ plt.xlabel(x_label)
+ plt.ylabel(y_label)
+ plt.legend(fontsize=12)
+ plt.title(title)
+ plt.tight_layout(pad=3, w_pad=3, h_pad=3)
+ plt.savefig(file_name)
+ plt.close()
--- /dev/null
+# Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http:#www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Internal use only.
+
+This file implements controlling APC PDU via telnet.
+"""
+
+import telnetlib
+
+
+class Control(object):
+ """ control APC via telnet """
+
+ @classmethod
+ def apc_telnet_make_choice(cls, telnet, choice):
+ """ select a choice """
+ telnet.read_until("Event Log")
+ telnet.read_until(">")
+ telnet.write(choice + "\r\n")
+
+ @classmethod
+ def apc_telnet_common_action(cls, telnet, check_str, action):
+ """ wait until a pattern and then write a line """
+ telnet.read_until(check_str)
+ telnet.write(action + "\r\n")
+
+ @classmethod
+ def control(cls, apc_ip, control_dict):
+ """
+ control APC
+
+ :param apc_ip: IP of APC
+ :param control_dict: dict with outlet ID and "ON" or "OFF"
+ """
+
+ for _outlet in control_dict:
+ assert 0 < _outlet < 9
+ assert control_dict[_outlet] in ["ON", "OFF"]
+
+ # telnet
+ # set timeout as 2s so that it won't waste time even can't access APC
+ tn = telnetlib.Telnet(host=apc_ip, timeout=5)
+ # log on
+ cls.apc_telnet_common_action(tn, "User Name :", "apc")
+ cls.apc_telnet_common_action(tn, "Password :", "apc")
+ # go to Device Manager
+ cls.apc_telnet_make_choice(tn, "1")
+ # go to Outlet Management
+ cls.apc_telnet_make_choice(tn, "2")
+ # go to Outlet Control/Configuration
+ cls.apc_telnet_make_choice(tn, "1")
+
+ # do select Outlet and control
+ for _outlet in control_dict:
+ # choose Outlet
+ cls.apc_telnet_make_choice(tn, str(_outlet))
+ # choose Control Outlet
+ cls.apc_telnet_make_choice(tn, "1")
+ # choose action
+ _action = control_dict[_outlet]
+ if "ON" in _action:
+ cls.apc_telnet_make_choice(tn, "1")
+ else:
+ cls.apc_telnet_make_choice(tn, "2")
+ # do confirm
+ cls.apc_telnet_common_action(tn, "cancel :", "YES")
+ cls.apc_telnet_common_action(tn, "continue...", "")
+ # return to Outlet Control/Configuration
+ cls.apc_telnet_make_choice(tn, "\033")
+ cls.apc_telnet_make_choice(tn, "\033")
+
+ # exit to main menu and logout
+ tn.write("\033\r\n")
+ tn.write("\033\r\n")
+ tn.write("\033\r\n")
+ tn.write("4\r\n")
+
+ @classmethod
+ def control_rest(cls, apc_ip, outlet, action):
+ outlet_list = range(1, 9)
+ outlet_list.remove(outlet)
+ cls.control(apc_ip, dict.fromkeys(outlet_list, action))
* pyyaml
* xunitgen
* netifaces
+ * matplotlib (if use Utility.LineChart)
To build document, we need to install ``Sphinx`` and ``sphinx-rtd-theme`` (you may replace this with your own theme).