Vim�UnDoεακό6Hζ0Θ0΅<ε[βo
Ή�ΧQ�Σ¦ρω mΫY    hotspot_controller = HotspotController( minary_wifi_server_url, minary_api_server_url
,



]{οL_Π7����]{ι¶υυ
5�_Π
����]{ιΈυ?    minary_api_server_url = os.environ["MINARY_API_SERVER_URL"]5�_Π
5����]{ιΎυE    minary_admin_api_server_url = os.environ["MINARY_API_SERVER_URL"]5�_Π
:����]{ιΏυ	import os-from wifi_controller import HotspotController from utils import CoinmineLogger!logger = CoinmineLogger(__name__)if __name__ == "__main__":/    logger.debug("Starting Hotspot Controller")A    minary_wifi_server_url = os.environ["MINARY_WIFI_SERVER_URL"]?    minary_api_server_url = os.environ["MINARY_API_SERVER_URL"]K    minary_admin_api_server_url = os.environ["MINARY_ADMIN_API_SERVER_URL"]Y    hotspot_controller = HotspotController(minary_wifi_server_url, minary_api_server_url)%    hotspot_controller.update_state()5�_Π5����]{ιΑυ5        minary_wifi_server_url, minary_api_server_url5�_Π
����]{ο#υ
K    minary_admin_api_server_url = os.environ["MINARY_ADMIN_API_SERVER_URL"]5�_Π5����]{οEυ
R        minary_wifi_server_url, minary_api_server_url, minary_admin_api_server_url5�_Π	
*����]{οIυ+    hotspot_controller = HotspotController(5        minary_wifi_server_url, minary_api_server_url5�_Π
	
,����]{οJυY    hotspot_controller = HotspotController( minary_wifi_server_url, minary_api_server_url5�_Π	

*����]{οKυ	import os-from wifi_controller import HotspotController from utils import CoinmineLogger!logger = CoinmineLogger(__name__)if __name__ == "__main__":/    logger.debug("Starting Hotspot Controller")A    minary_wifi_server_url = os.environ["MINARY_WIFI_SERVER_URL"]?    minary_api_server_url = os.environ["MINARY_API_SERVER_URL"]X    hotspot_controller = HotspotController(minary_wifi_server_url, minary_api_server_url    )%    hotspot_controller.update_state()5�η�
VimŸUnDoх3О‹рЋc|@HЉцтŒSрЂP"м‘“@'ве•ˆJ((((].CЫ_аџџџџ].@,ѕѕ5_аџџџџ].@<ѕѕ5_аџџџџ].@=ѕ5_аџџџџ].@Dѕ	
ѕ
5_а	џџџџ].@Fѕ	        pass5_а џџџџ].@Ÿѕ@            logger.debug("docker health check reported healthy")5_а,џџџџ].@Ђѕ?            logger.debug("docke health check reported healthy")5_а	.џџџџ].@Їѕ/            logger.debug("{} reported healthy")5_а
	Lџџџџ].@Вѕclass BaseHealthChecker:    def check(self):        if self._is_healthy():O            logger.debug("{} reported healthy".format(self.__class__.__name__))
        else:W            logger.error("docker health check reported unhealthy, restarting services")H            DockerHealthChecker._restart_minary_compose(self.remedy_cmd)    def _is_healthy(self):        pass    def remedy(self):        pass5_а	
-џџџџ].@Йѕ
W            logger.error("docker health check reported unhealthy, restarting services")5_а
Dџџџџ].@Пѕ
F            logger.error("{} reported unhealthy, restarting services")5_аHџџџџ].@Чѕ
I            logger.error("{} reported unhealthy, running remedy command")5_а
Oџџџџ].@Яѕ
R            logger.error("{} reported unhealthy, running remedy command".format())ѕ
5_аfџџџџ].@аѕ
class BaseHealthChecker:    def check(self):        if self._is_healthy():O            logger.debug("{} reported healthy".format(self.__class__.__name__))
        else:i            logger.error("{} reported unhealthy, running remedy command".format(self.__class__.__name__))H            DockerHealthChecker._restart_minary_compose(self.remedy_cmd)    def _is_healthy(self):        pass    def remedy(self):        pass5_аџџџџ].BŠѕѕ5_аџџџџ].B‹ѕ5_аџџџџ].BŒѕ from utils import CoinmineLogger!logger = CoinmineLogger(__name__)class BaseHealthChecker:    def check(self):        if self._is_healthy():O            logger.debug("{} reported healthy".format(self.__class__.__name__))
        else:            logger.error(G                "{} reported unhealthy, running remedy command".format(+                    self.__class__.__name__                )
            )H            DockerHealthChecker._restart_minary_compose(self.remedy_cmd)    def _is_healthy(self):        pass    def remedy(self):        pass5_аџџџџ].B“ѕH            DockerHealthChecker._restart_minary_compose(self.remedy_cmd)5_а(џџџџ].BЁѕ9            self._restart_minary_compose(self.remedy_cmd)5_аџџџџ].B­ѕ1            self._run_remedy_cmd(self.remedy_cmd)5_аџџџџ].BЧѕѕ5_аџџџџ].BШѕ        pass5_аџџџџ].BЩѕ    def remedy(self):5_аџџџџ].BЮѕ!    def _run_remedy_remedy(self):5_аџџџџ].Bиѕѕ5_аџџџџ].Bйѕ5_аџџџџ].Bрѕ    def _run_remedy_cmd(self):5_а#џџџџ].Bчѕ,        subprocess.run(shlex.split(command))5_а.џџџџ].Bь	ѕ7        subprocess.run(shlex.split(self.remed_command))5_а џџџџ].Bё
ѕ    def _run_remedy_cmd(self):5_а! џџџџ].Bїѕ1            self._run_remedy_cmd(self.remedy_cmd)5_а "!џџџџV"].Cѕ        ѕ5_а!#"џџџџV"].Cѕ$        raise("Should be implement")5_а"$#џџџџV"].Cѕ0        raise("This method Should be implement")5_а#%$.џџџџV"].Cѕ0        raise("This method should be implement")5_а$&%DџџџџV"].Cѕimport subprocessimport shlex from utils import CoinmineLogger!logger = CoinmineLogger(__name__)class BaseHealthChecker:    def check(self):        if self._is_healthy():O            logger.debug("{} reported healthy".format(self.__class__.__name__))
        else:            logger.error(G                "{} reported unhealthy, running remedy command".format(+                    self.__class__.__name__                )
            )5            self._run_remedy_command(self.remedy_cmd)    def _is_healthy(self):G        raise("This method should be implemented by the derived class")        pass"    def _run_remedy_command(self):8        subprocess.run(shlex.split(self.remedy_command))5_а%'&џџџџV"].Cѕ        pass5_а&('џџџџV].CЩѕimport subprocessimport shlex from utils import CoinmineLogger!logger = CoinmineLogger(__name__)class BaseHealthChecker:    def check(self):        if self._is_healthy():O            logger.debug("{} reported healthy".format(self.__class__.__name__))
        else:            logger.error(G                "{} reported unhealthy, running remedy command".format(+                    self.__class__.__name__                )
            )5            self._run_remedy_command(self.remedy_cmd)    def _is_healthy(self):H        raise ("This method should be implemented by the derived class")"    def _run_remedy_command(self):8        subprocess.run(shlex.split(self.remedy_command))5_а'(џџџџV].CЪѕ5_а
6џџџџ].@Эѕ
8            logger.debug("{} reported healthy".format())5чЊ
Example #3
0
Vim�UnDo�[�'�:��K~|!VE�ڵ_��f�t��Պ���2        logger.debug("running cmd={}".format(cmd))�



\���_�++����\��3�*,�H        logger.debug("Light & Sound has " "firmware={}".format(fw_hash))5�_�+����+','V'\��;�*+E        logger.debug("Light & Sound has firmware={}".format(fw_hash))W        logger.debug("Light & Sound repo has " "firmware={}".format(published_fw_hash))5�_�+����+'+'V'\��<�*+5�_��-����+'+'V'\��P����D            chunk_data = result[(chunk * 128) : ((chunk + 1) * 128)]5�_��-����+'+'V'\��Q��import waveimport zlib
import struct
import serialimport time	import reimport subprocessimport shlex from utils import CoinmineLogger!logger = CoinmineLogger(__name__)class TeensyInterface:J    def __init__(self, serial_path, script_path=None, serial_baud=115200):&        self.serial_path = serial_path&        self.serial_baud = serial_baud?        self.firmware_path = "{}/firmware/".format(script_path)5        self.helpers_path = script_path + "/helpers/"2        self.asset_path = script_path + "/assets/"    def set_serial_port(self):)        self.serial_port = serial.Serial(;            self.serial_path, self.serial_baud, timeout=0.1	        )3    def update_firmware_if_version_different(self):$        fw_hash = self.get_version()        published_fw_hash = ""        try:U            version_file = open(self.firmware_path + "thunder-and-lightning.version")?            published_fw_hash = version_file.readline().strip()        except IOError:            logger.warn(A                "Could not open {}thunder-and-lightning.version."M                "Skipping firmware update checks.".format(self.firmware_path)
            )            return(        if fw_hash != published_fw_hash:            logger.warn(Q                "Need to update from {} to {}".format(fw_hash, published_fw_hash)
            )#            self._update_firmware()            return True        return False+    def flash_audio_files_if_changed(self)::        # Map all of the slots on the flash to audio files        audio_files = [1            (0, self.asset_path + "PowerOn.wav"),3            (1, self.asset_path + "PowerDown.wav"),5            (2, self.asset_path + "WifiConnect.wav"),8            (3, self.asset_path + "StartedSuccess.wav"),	        ]&        for audio_file in audio_files:5            file_crc = self.calc_crc32(audio_file[1])            device_crc = 0            try:;                device_crc = self.read_crc32(audio_file[0])            except ValueError:                device_crc = 0            logger.info('                "{} -- File CRC32: {} "Q                "-- Device CRC32: {}".format(audio_file[1], file_crc, device_crc)
            )&            if file_crc != device_crc:-                self.store_audio(*audio_file);    def send_packet(self, op_code, argument, data=bytes()):V        send_data = bytes([0xAA, op_code, argument, len(data)]) + data + bytes([0x55]))        self.serial_port.write(send_data)    def read_response(self):        ret = []5        chr = self.serial_port.read().decode("utf-8")        while chr != "\n":            if chr != "\r":                ret += chr9            chr = self.serial_port.read().decode("utf-8")        return "".join(ret)7    def handle_response(self, function_name, response):        """O        OpCode:[OpCode]::[Return String]::Command [Success|Failed]::[ErrorCode]6        E.g. OpCode:23::2253080301::Command Success::0        """        try:#            regex_match = re.match(-                "OpCode:(?P<opcode>[0-9]+)::")                "(?P<return_string>.*)::">                "Command (?P<success_string>Success|Failed)::")                "(?P<error_code>[0-9]+)",                response,
            )            if regex_match:B                return_string = regex_match.group("return_string")J                success = regex_match.group("success_string") == "Success"?                err_code = int(regex_match.group("error_code"))                if not success:%                    raise ValueError(;                        "ThunderAndLightningInterface::{} "B                        "error {}".format(function_name, err_code)                    )$                return return_string            else:!                raise ValueError(4                    "ThunderAndLightningInterface::"?                    "Bad Response Format ({})".format(response)                )        except Exception:            pass    def get_version(self):        self.send_packet(0, 0)H        return self.handle_response("get_version", self.read_response())1    def set_lights(self, state_bin, duration=33):K        # Keep polling the device until we have a free command slot to fill         while self.query() == 0:            time.sleep(0.1)8        self.send_packet(0x04, int(duration), state_bin)@        self.handle_response("set_lights", self.read_response())    def query(self):$        self.send_packet(0x07, 0x00)G        return int(self.handle_response("query", self.read_response()))'    def play_audio(self, sample_index):)        self.send_packet(1, sample_index)@        self.handle_response("play_audio", self.read_response())3    def store_audio(self, sample_index, file_name):/        wave_reader = wave.open(file_name, "r")>        chans, res, fs, length, _, _ = wave_reader.getparams()*        nframes = wave_reader.getnframes()O        data = struct.unpack("<%dh" % nframes, wave_reader.readframes(nframes))        converted = []        for value in data:-            converted.append(value + 2 ** 15):        result = struct.pack("<%dH" % nframes, *converted)         crc = zlib.crc32(result)8        # calculate number of chunks to send (fake ceil)/        chunks = int(len(result) / 128.0 + 0.5)+        # initiate a sample write operationS        self.send_packet(2, sample_index, struct.pack("=3I", crc, chunks, nframes))A        self.handle_response("store_audio", self.read_response())#        for chunk in range(chunks):C            chunk_data = result[(chunk * 128): ((chunk + 1) * 128)]@            packed_bytes = struct.pack("=I", chunk) + chunk_dataH            logger.debug("Sending chunk {} of {}".format(chunk, chunks))<            self.send_packet(22, sample_index, packed_bytes)E            self.handle_response("store_audio", self.read_response())$    def calc_crc32(self, file_name):/        wave_reader = wave.open(file_name, "r")>        chans, res, fs, length, _, _ = wave_reader.getparams()*        nframes = wave_reader.getnframes()O        data = struct.unpack("<%dh" % nframes, wave_reader.readframes(nframes))        converted = []        for value in data:-            converted.append(value + 2 ** 15):        result = struct.pack("<%dH" % nframes, *converted)!        return zlib.crc32(result)'    def read_crc32(self, sample_index):*        self.send_packet(23, sample_index)L        return int(self.handle_response("read_crc32", self.read_response()))    def _update_firmware(self):@        # teensy_loader_cli --mcu=TEENSYLC -s $(HEX_OUTPUT_FILE)        cmd = ("            "{}teensy_loader_cli "            "--mcu=TEENSYLC "7            "-s -v {}thunder-and-lightning.hex".format(5                self.helpers_path, self.firmware_path
            )	        )2        logger.debug("running cmd={}".format(cmd))4        subprocess.run(shlex.split(cmd), timeout=10)5�_��-����''V'\��S����D            chunk_data = result[(chunk * 128) : ((chunk + 1) * 128)]5�_��-����''V'\��T��import waveimport zlib
import struct
import serialimport time	import reimport subprocessimport shlex from utils import CoinmineLogger!logger = CoinmineLogger(__name__)class TeensyInterface:J    def __init__(self, serial_path, script_path=None, serial_baud=115200):&        self.serial_path = serial_path&        self.serial_baud = serial_baud?        self.firmware_path = "{}/firmware/".format(script_path)5        self.helpers_path = script_path + "/helpers/"2        self.asset_path = script_path + "/assets/"    def set_serial_port(self):)        self.serial_port = serial.Serial(;            self.serial_path, self.serial_baud, timeout=0.1	        )3    def update_firmware_if_version_different(self):$        fw_hash = self.get_version()        published_fw_hash = ""        try:U            version_file = open(self.firmware_path + "thunder-and-lightning.version")?            published_fw_hash = version_file.readline().strip()        except IOError:            logger.warn(A                "Could not open {}thunder-and-lightning.version."M                "Skipping firmware update checks.".format(self.firmware_path)
            )            return(        if fw_hash != published_fw_hash:            logger.warn(Q                "Need to update from {} to {}".format(fw_hash, published_fw_hash)
            )#            self._update_firmware()            return True        return False+    def flash_audio_files_if_changed(self)::        # Map all of the slots on the flash to audio files        audio_files = [1            (0, self.asset_path + "PowerOn.wav"),3            (1, self.asset_path + "PowerDown.wav"),5            (2, self.asset_path + "WifiConnect.wav"),8            (3, self.asset_path + "StartedSuccess.wav"),	        ]&        for audio_file in audio_files:5            file_crc = self.calc_crc32(audio_file[1])            device_crc = 0            try:;                device_crc = self.read_crc32(audio_file[0])            except ValueError:                device_crc = 0            logger.info('                "{} -- File CRC32: {} "Q                "-- Device CRC32: {}".format(audio_file[1], file_crc, device_crc)
            )&            if file_crc != device_crc:-                self.store_audio(*audio_file);    def send_packet(self, op_code, argument, data=bytes()):V        send_data = bytes([0xAA, op_code, argument, len(data)]) + data + bytes([0x55]))        self.serial_port.write(send_data)    def read_response(self):        ret = []5        chr = self.serial_port.read().decode("utf-8")        while chr != "\n":            if chr != "\r":                ret += chr9            chr = self.serial_port.read().decode("utf-8")        return "".join(ret)7    def handle_response(self, function_name, response):        """O        OpCode:[OpCode]::[Return String]::Command [Success|Failed]::[ErrorCode]6        E.g. OpCode:23::2253080301::Command Success::0        """        try:#            regex_match = re.match(-                "OpCode:(?P<opcode>[0-9]+)::")                "(?P<return_string>.*)::">                "Command (?P<success_string>Success|Failed)::")                "(?P<error_code>[0-9]+)",                response,
            )            if regex_match:B                return_string = regex_match.group("return_string")J                success = regex_match.group("success_string") == "Success"?                err_code = int(regex_match.group("error_code"))                if not success:%                    raise ValueError(;                        "ThunderAndLightningInterface::{} "B                        "error {}".format(function_name, err_code)                    )$                return return_string            else:!                raise ValueError(4                    "ThunderAndLightningInterface::"?                    "Bad Response Format ({})".format(response)                )        except Exception:            pass    def get_version(self):        self.send_packet(0, 0)H        return self.handle_response("get_version", self.read_response())1    def set_lights(self, state_bin, duration=33):K        # Keep polling the device until we have a free command slot to fill         while self.query() == 0:            time.sleep(0.1)8        self.send_packet(0x04, int(duration), state_bin)@        self.handle_response("set_lights", self.read_response())    def query(self):$        self.send_packet(0x07, 0x00)G        return int(self.handle_response("query", self.read_response()))'    def play_audio(self, sample_index):)        self.send_packet(1, sample_index)@        self.handle_response("play_audio", self.read_response())3    def store_audio(self, sample_index, file_name):/        wave_reader = wave.open(file_name, "r")>        chans, res, fs, length, _, _ = wave_reader.getparams()*        nframes = wave_reader.getnframes()O        data = struct.unpack("<%dh" % nframes, wave_reader.readframes(nframes))        converted = []        for value in data:-            converted.append(value + 2 ** 15):        result = struct.pack("<%dH" % nframes, *converted)         crc = zlib.crc32(result)8        # calculate number of chunks to send (fake ceil)/        chunks = int(len(result) / 128.0 + 0.5)+        # initiate a sample write operationS        self.send_packet(2, sample_index, struct.pack("=3I", crc, chunks, nframes))A        self.handle_response("store_audio", self.read_response())#        for chunk in range(chunks):C            chunk_data = result[(chunk * 128): ((chunk + 1) * 128)]@            packed_bytes = struct.pack("=I", chunk) + chunk_dataH            logger.debug("Sending chunk {} of {}".format(chunk, chunks))<            self.send_packet(22, sample_index, packed_bytes)E            self.handle_response("store_audio", self.read_response())$    def calc_crc32(self, file_name):/        wave_reader = wave.open(file_name, "r")>        chans, res, fs, length, _, _ = wave_reader.getparams()*        nframes = wave_reader.getnframes()O        data = struct.unpack("<%dh" % nframes, wave_reader.readframes(nframes))        converted = []        for value in data:-            converted.append(value + 2 ** 15):        result = struct.pack("<%dH" % nframes, *converted)!        return zlib.crc32(result)'    def read_crc32(self, sample_index):*        self.send_packet(23, sample_index)L        return int(self.handle_response("read_crc32", self.read_response()))    def _update_firmware(self):@        # teensy_loader_cli --mcu=TEENSYLC -s $(HEX_OUTPUT_FILE)        cmd = ("            "{}teensy_loader_cli "            "--mcu=TEENSYLC "7            "-s -v {}thunder-and-lightning.hex".format(5                self.helpers_path, self.firmware_path
            )	        )2        logger.debug("running cmd={}".format(cmd))4        subprocess.run(shlex.split(cmd), timeout=10)5�_�	�����''V'\�������2        logger.debug("running cmd={}".format(cmd))5�_�
	�.����''V'\�������C        logger.debug("running firmware updater cmd={}".format(cmd))5�_�	
�.����''V'\�������C        logger.debug("running firmware update" cmd={}".format(cmd))5�_�
�.����''V'\�������.        logger.debug("running firmware update"5�_�
�6����''V'\�������7        logger.debug("running firmware update", {"cmd"}5�_�
�<����''V'\�������<        logger.debug("running firmware update", {"cmd": cmd}5��
Vim�UnDo����}}"'�q��K�j�[|u��!Km/�|φ��!            logger.info(response)<2222^{_�9����996v6]�8:�8        time.sleep(0.03333 - (self.start - time.time()))5�_�8����996v6]�8:�        �9:��8:�5�_�:����::6v6]�9;�        time.sleep()5�_�9����::6v6]�9;�        �9;�5�_�:&����;;6v6]�9;�'        logger.debug("sleeping for {}")5�_�1����;;6v6]���13��12�5�_�2����<<6v6]���13�:        logger.debug("sleeping for {}".format(sleep_time))5�_�	2����<<6v6]���13�        logger.debug("))5�_�
	2����<<6v6]���13�        logger.debug("")5�_�	
A����<<6v6]���BD��BC��AC�5�_�
C����<<6v6]��BD�.        logger.debug("running animation step")5�_�
C����<<6v6]��BD�        logger.debug("")5�_�
C����<<6v6]��BD�;        logger.debug("updating state of ambiance from api")5�_�
C,����<<6v6]��BD�I        logger.debug("attempting to updating state of ambiance from api")5�_�D)����<<6v6]��DF��DE�5�_�E����EEV]��DF�G        logger.debug("attempting to update state of ambiance from api")5�_�E����EEV]��DF�K            logger.debug("attempting to update state of ambiance from api")5�_�E����EEV]��DF�            logger.debug("")5�_�EB����EEV]�'�DF�C            logger.debug("accumulated seconds waiting reacher 10s")5�_�EA����EEV]�/�DF�b            logger.debug("accumulated seconds waiting reacher 10s".format(self.accum_ten_seconds))5�_�CD����EEV]�6�BD�G        logger.debug("attempting to update state of ambiance from api")�CD�5�_�Co����EEV]�<�BD�q        logger.debug("attempting to update state of ambiance from api timer={}".format(self.accum_ten_seconds))")5�_�Cn����EEV]�<��import timeUfrom thunder_and_lightning.animations import WifiSearch, WifiFound, Mining, PowerDown from utils import CoinmineLogger+from utils.requests import CoinmineRequests!logger = CoinmineLogger(__name__)class AmbianceController:    def __init__(
        self,        teensy_interface,        state_json,#        minary_ambiance_server_url,        animation_queue,        num_led=10,    ):        self.state = None%        self.last_state_json = dict()$        self.state_json = state_json        self.num_led = num_led$        self.ambiance_enabled = True0        self.teensy_interface = teensy_interfaceD        self.minary_ambiance_server_url = minary_ambiance_server_url"        self.accum_ten_seconds = 0.        self.animation_queue = animation_queue    def turn_lights_off(self):        self.state.reset()=        self.teensy_interface.set_lights(self.state.render())%    def run_poweroff_animation(self):!        if self.ambiance_enabled:9            if self.teensy_interface.serial_port.is_open:9                self.teensy_interface.serial_port.close()8                self.teensy_interface.serial_port.open()1            self.run_state_animation(PowerDown())"            self.turn_lights_off())    def run_state_animation(self, state):        self.state = state        while True:            if self.state.done:                return4            self._play_audio_and_animate_one_frame()!    def run_animation_step(self):.        logger.debug("running animation step")        self._start_timer()!        self._update_state_json()%        self._set_prioritized_state()        if self.state:4            self._play_audio_and_animate_one_frame())        self.accum_ten_seconds += 0.033339        sleep_time = 0.03333 - (self.start - time.time()):        logger.debug("sleeping for {}".format(sleep_time))        time.sleep(sleep_time)    def _start_timer(self):         self.start = time.time()!    def _update_state_json(self):o        logger.debug("attempting to update state of ambiance from api timer={}".format(self.accum_ten_seconds))*        if self.accum_ten_seconds >= 10.0:k            logger.debug("accumulated seconds waiting reacher 10s timer={}".format(self.accum_ten_seconds))&            self.accum_ten_seconds = 03            self.state_json = CoinmineRequests.get(8                self.minary_ambiance_server_url, "state"
            )K            self.ambiance_enabled = self.state_json.get("ambiance_enabled")%    def _set_prioritized_state(self):9        if not (self.state_json == self.last_state_json):            updated = set(                [                    item[0]<                    for item in set(self.state_json.items())7                    ^ set(self.last_state_json.items())                ]
            )?            logger.info("full_status diff: {}".format(updated))            field = "none"            queue_list = []O            if "wifi_search" in updated and self.state_json.get("wifi_search"):%                field = "wifi_search"4                queue_list.append((0, WifiSearch()))M            if "wifi_found" in updated and self.state_json.get("wifi_found"):$                field = "wifi_found"3                queue_list.append((0, WifiFound()))A            if "coin" in updated and self.state_json.get("coin"):                field = "coin"G                queue_list.append((1, Mining(self.state_json["coin"])))M            if "power_down" in updated and self.state_json.get("power_down"):$                field = "power_down"3                queue_list.append((0, PowerDown()));            self.animation_queue.set_animations(queue_list)F            next_animation = self.animation_queue.get_next_animation()            if next_animation:+                self.state = next_animation            logger.info(8                "triggering {} switch: {} -> {}".format(2                    self.state.__class__.__name__,<                    self.last_state_json.get(field, "none"),/                    self.state_json.get(field),                )
            )2            self.last_state_json = self.state_json0    def _play_audio_and_animate_one_frame(self):!        if self.ambiance_enabled:,            if hasattr(self.state, "index"):)                if self.state.index == 0:(                    if self.state.sound:J                        self.teensy_interface.play_audio(self.state.sound)%                elif self.state.done:&                    self.state.reset()!                self.state.step()E                self.teensy_interface.set_lights(self.state.render())            else:2                logger.debug("skipping animation")
        else:"            self.turn_lights_off()5�_�5����V]�F�57�5�_�7����V]�G�79�            �79�5�_�8$����V]�V�79�&            logger.debug("new state=")5�_�8&����V]�X�79�)            logger.debug("new state={]}")5�_�8'����V]�X�79�(            logger.debug("new state={}")5�_�8����V]�e�79�;            logger.debug("new state={}".format(self.state))5�_�!8����V]���79�7            logger.debug("state={}".format(self.state))5�_�" !6����V]���69��67�5�_�!#"7����V]���67        if self.state:5�_�"$#7����77V]���68�?            logger.debug("setting state={}".format(self.state))5�_�#%$7����77V]���68�;        logger.debug("setting state={}".format(self.state))5�_�$&%L����LP
V]��#�KL            logger.debug(J                "accumulated seconds waiting reacher 10s timer={}".format(*                    self.accum_ten_seconds                )
            )5�_�%'&F����JFV]��%�EF        logger.debug(N            "attempting to update state of ambiance from api timer={}".format(&                self.accum_ten_seconds
            )	        )5�_�&('E����FFV]��(�DE5�_�')(>����EEV]��	�=>:        logger.debug("sleeping for {}".format(sleep_time))5�_�(*)7����DDV]��(�673        logger.debug("state={}".format(self.state))5�_�)+*2����CCV]���12.        logger.debug("running animation step")5�_�*,+7����BBV]���67?            logger.debug("setting state={}".format(self.state))5�_�+-,:����^z��;=��;<��:<�5�_�,.-<����<<V^z��;=�!            logger.info(response)5�_�-/.<����<<V^z��;=�        logger.info(response)5�_�.0/<����<<V^z��;=�        logger.info()5�_�/10<����<<V^z��;=�         logger.info(sleep_timee)5�_�021<����<<V^z��;=�        logger.info(sleep_time)5�_�12<7����<<V^z��;=�7        logger.info("sleep time: {}".format(sleep_time)5�_�! 6����V]���67��67�        if self.state:?            logger.debug("setting state={}".format(self.state))5�_�EA����EEV]�5�DF�A            logger.debug("accumulated seconds waiting reacher 10s5��
VimЯUnDoеb3длуе,=ЦХ–#¤#УUH[ы%кWоЖHhЃШƒP                s.sendall(b'{"id":0,"jsonrpc":"2.0","method":"miner_getstat1"}')9L
	_†Џx	_–(W¤¤¤¤^Вb-х')X        miner_status["mining"] = MinerRequests._is_hashing(miner_status.get("hashrate"))5Б_–([¤¤¤¤^Вb/х
import socketimport json from utils import CoinmineLogger+from utils.requests import CoinmineRequests!logger = CoinmineLogger(__name__)class MinerRequests:    @staticmethod%    def get_miner_status(coin, urls):        # we assume not mining        miner_status = {            "uptime": 0,            "hashrate": 0,!            "hashrate_list": [0],            "pool": "",            "errors": [],	        }        try:            miners = {W                "ethereum": lambda: MinerRequests.get_claymore_stats(urls["claymore"]),T                "zcash": lambda: MinerRequests.get_claymore_stats(urls["claymore"]),O                "monero": lambda: MinerRequests.get_xmrig_stats(urls["xmrig"]),S                "grin": lambda: MinerRequests.get_lolminer_stats(urls["lolminer"]),G                "hashcat": lambda: MinerRequests.get_hashtopolis_stats('                    urls["hashtopolis"]                ),X                "handshake": lambda: MinerRequests.get_sixminer_stats(urls["sixminer"]),K                None: lambda: {"errors": "missing coin value from config"},
            }=            miner_status = {**miner_status, **miners[coin]()}I            logger.debug("received miner status {}".format(miner_status))        except Exception as e:G            logger.warning("failed to get miner status e={}".format(e))]        miner_status["mining"] = MinerRequests._is_hashing(miner_status.get("hashrate") or 0)        return miner_status    @staticmethod,    def get_claymore_stats(claymore_socket):        try:H            with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:                logger.debug(>                    "attempting to connect to claymore rpc on"1                    " {}".format(claymore_socket)                )*                s.connect(claymore_socket)9                logger.debug("connected to claymore rpc")                 s.settimeout(60)P                s.sendall(b'{"id":0,"jsonrpc":"2.0","method":"miner_getstat1"}')C                logger.debug("sent json for stats to claymore rpc")#                data = s.recv(1024)?                logger.debug("received data from claymore rpc")'            string_data = data.decode()/            json_data = json.loads(string_data)-            result_list = json_data["result"]*            uptime_in_min = result_list[1]:            accepted_shares = result_list[2].split(";")[1]:            rejected_shares = result_list[2].split(";")[2]%            hashrate = result_list[3]            # multigpu            if ";" in hashrate:E                hashrate_list = list(map(float, hashrate.split(";")))-                hashrate = sum(hashrate_list)            else:1                hashrate_list = [float(hashrate)]4            fan_speed = result_list[6].split(";")[1]/            temp = result_list[6].split(";")[0]!            pool = result_list[7]            stats = {4                "uptime": int(float(uptime_in_min)),*                "hashrate": int(hashrate),/                "hashrate_list": hashrate_list,8                "accepted_shares": int(accepted_shares),8                "rejected_shares": int(rejected_shares),,                "fan_speed": int(fan_speed),"                "temp": int(temp),                "pool": pool,
            }C            logger.debug("claymore socket stats: {}".format(stats))            return stats        except Exception as e:            logger.warning(T                "could not handle sending or receiving from socket:" " {}".format(e)
            )B            return {"errors": "claymore http service unavailable"}    @staticmethod)    def get_xmr_stak_stats(xmr_stak_url):        try:B            stats = CoinmineRequests.get(xmr_stak_url, "api.json").            pool = stats["connection"]["pool"]9            uptime_in_sec = stats["connection"]["uptime"]4            # will report 0 if a single thread fails4            hashrate = stats["hashrate"]["total"][0]             if hashrate is None:                hashrate = 0=            accepted_shares = stats["results"]["shares_good"]P            rejected_shares = stats["results"]["shares_total"] - accepted_shares8            # None values come from failed gpus/threads,7            # we want to accurately report the hashrate$            # even if a thread fails8            hashrate_list = stats["hashrate"]["threads"]            # convert None to 0P            hashrate_list = [0 if i[0] is None else i[0] for i in hashrate_list]>            total_hashrate_threads = round(sum(hashrate_list))            return {2                "uptime": int(uptime_in_sec / 60),D                "hashrate": int(hashrate) or total_hashrate_threads,/                "hashrate_list": hashrate_list,8                "accepted_shares": int(accepted_shares),8                "rejected_shares": int(rejected_shares),                "pool": pool,
            }        except Exception as e:L            logger.warning("could not return xmr-stak stats e={}".format(e))B            return {"errors": "xmr-stak http service unavailable"}    @staticmethod+    def get_nanominer_stats(nanominer_url):        try:            hashrate = 0            hashrate_list = []            accepted_shares = 0            rejected_shares = 0            uptime = 0@            stats = CoinmineRequests.get(nanominer_url, "stats")&            algs = stats["Algorithms"]            adapter = 0            for alg in algs:S                values = next(iter(alg.values()))  # gets the first value from dict/                algorithm = list(alg.keys())[0]>                hashrate += float(values["Total"]["Hashrate"])C                accepted_shares += int(values["Total"]["Accepted"])A                rejected_shares += int(values["Total"]["Denied"])0                pool = values.pop("CurrentPool")/                del values["ReconnectionCount"]#                del values["Total"]1                for key, value in values.items():7                    if key == "GPU {}".format(adapter):$                        adapter += 12                        if algorithm == "RandomX":>                            # pass on gpu hashrates on randomx$                            continueB                    hashrate_list.append(float(value["Hashrate"]))&            uptime = stats["WorkTime"]            return {%                "hashrate": hashrate,/                "hashrate_list": hashrate_list,!                "uptime": uptime,3                "accepted_shares": accepted_shares,3                "rejected_shares": rejected_shares,                "pool": pool,
            }        except Exception as e:M            logger.warning("could not return nanominer stats e={}".format(e))C            return {"errors": "nanominer http service unavailable"}    @staticmethodF    def get_teamredminer_stats(teamredminer_socket=("0.0.0.0", 4028)):        stats = {}        try:A            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)            logger.debug(>                "attempting to connect to teamredminer rpc on"1                " {}".format(teamredminer_socket)
            )*            s.connect(teamredminer_socket)9            logger.debug("connected to teamredminer rpc")            s.settimeout(60)!            s.sendall(b"summary")C            logger.debug("sent json for stats to teamredminer rpc")            data = s.recv(1024)?            logger.debug("received data from teamredminer rpc")'            string_data = data.decode().            list_data = string_data.split(",")=            stats["uptime"] = int(list_data[5].split("=")[1])I            hashrate = round(float(list_data[6].split("=")[1]) * 10e5, 3)(            stats["hashrate"] = hashrate/            stats["hashrate_list"] = [hashrate]G            stats["hardware_errors"] = int(list_data[14].split("=")[1])G            stats["accepted_shares"] = int(list_data[12].split("=")[1])G            stats["rejected_shares"] = int(list_data[13].split("=")[1])        except Exception as e:            logger.warning(Q                "could not handle sending or receiving from socket: {}".format(e)
            )        return stats    @staticmethod/    def get_hashtopolis_stats(hashtopolis_url):>        stats = CoinmineRequests.get(hashtopolis_url, "stats").        stats["hashrate"] = stats.pop("speed")4        stats["hashrate_list"] = [stats["hashrate"]]8        stats["accepted_shares"] = stats.pop("accepted")8        stats["uptime"] = stats.pop("uptime_in_seconds")        return stats    @staticmethod)    def get_lolminer_stats(lolminer_url):        stats = {}        try:@            data = CoinmineRequests.get(lolminer_url, "summary")            stats = {4                "uptime": data["Session"]["Uptime"],C                "hashrate": data["Session"]["Performance_Summary"],N                "hashrate_list": [gpu["Performance"] for gpu in data["GPUs"]],?                "accepted_shares": data["Session"]["Accepted"],?                "rejected_shares": data["Session"]["Submitted"].                - data["Session"]["Accepted"],8                "pool": data["Stratum"]["Current_Pool"],
            }        except Exception as e:H            logger.warning("could not get lolminer stats: {}".format(e))        return stats    @staticmethod*    def get_sixminer_stats(handshake_url):;        return MinerRequests.get_local_stats(handshake_url)    @staticmethod#    def get_xmrig_stats(xmrig_url):        stats = {}        try:?            data = CoinmineRequests.get(xmrig_url, "1/summary")            stats = {)                "uptime": data["uptime"],9                "hashrate": data["hashrate"]["total"][0],W                "hashrate_list": [thread[0] for thread in data["hashrate"]["threads"]],B                "accepted_shares": data["results"]["shares_good"],B                "rejected_shares": data["results"]["shares_total"]1                - data["results"]["shares_good"],3                "pool": data["connection"]["pool"],
            }        except Exception as e:E            logger.warning("could not get xmrig stats: {}".format(e))        return stats    @staticmethod    def get_local_stats(url):        stats = {}        try:5            data = CoinmineRequests.get(url, "stats")W            stats = {"hashrate": data["hashrate"], "hashrate_list": [data["hashrate"]]}        except Exception as e:E            logger.warning("could not get local stats: {}".format(e))        return stats    @staticmethod    def _is_hashing(hashrate):$        return bool(float(hashrate))5Б_–yC¤¤¤¤^Вd)хxz
D                "hashrate": int(hashrate) or total_hashrate_threads,5Б_–ц8¤¤¤¤^Вdѓххч
9                "hashrate": data["hashrate"]["total"][0],5Б_–ч+¤¤¤¤^Вiохцш
W                "hashrate_list": [thread[0] for thread in data["hashrate"]["threads"]],5Б_–	ч/¤¤¤¤^Вiрх

import socketimport json from utils import CoinmineLogger+from utils.requests import CoinmineRequests!logger = CoinmineLogger(__name__)class MinerRequests:    @staticmethod%    def get_miner_status(coin, urls):        # we assume not mining        miner_status = {            "uptime": 0,            "hashrate": 0,!            "hashrate_list": [0],            "pool": "",            "errors": [],	        }        try:            miners = {W                "ethereum": lambda: MinerRequests.get_claymore_stats(urls["claymore"]),T                "zcash": lambda: MinerRequests.get_claymore_stats(urls["claymore"]),O                "monero": lambda: MinerRequests.get_xmrig_stats(urls["xmrig"]),S                "grin": lambda: MinerRequests.get_lolminer_stats(urls["lolminer"]),G                "hashcat": lambda: MinerRequests.get_hashtopolis_stats('                    urls["hashtopolis"]                ),X                "handshake": lambda: MinerRequests.get_sixminer_stats(urls["sixminer"]),K                None: lambda: {"errors": "missing coin value from config"},
            }=            miner_status = {**miner_status, **miners[coin]()}I            logger.debug("received miner status {}".format(miner_status))        except Exception as e:G            logger.warning("failed to get miner status e={}".format(e));        miner_status["mining"] = MinerRequests._is_hashing(-            miner_status.get("hashrate") or 0	        )        return miner_status    @staticmethod,    def get_claymore_stats(claymore_socket):        try:H            with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:                logger.debug(>                    "attempting to connect to claymore rpc on"1                    " {}".format(claymore_socket)                )*                s.connect(claymore_socket)9                logger.debug("connected to claymore rpc")                 s.settimeout(60)P                s.sendall(b'{"id":0,"jsonrpc":"2.0","method":"miner_getstat1"}')C                logger.debug("sent json for stats to claymore rpc")#                data = s.recv(1024)?                logger.debug("received data from claymore rpc")'            string_data = data.decode()/            json_data = json.loads(string_data)-            result_list = json_data["result"]*            uptime_in_min = result_list[1]:            accepted_shares = result_list[2].split(";")[1]:            rejected_shares = result_list[2].split(";")[2]%            hashrate = result_list[3]            # multigpu            if ";" in hashrate:E                hashrate_list = list(map(float, hashrate.split(";")))-                hashrate = sum(hashrate_list)            else:1                hashrate_list = [float(hashrate)]4            fan_speed = result_list[6].split(";")[1]/            temp = result_list[6].split(";")[0]!            pool = result_list[7]            stats = {4                "uptime": int(float(uptime_in_min)),*                "hashrate": int(hashrate),/                "hashrate_list": hashrate_list,8                "accepted_shares": int(accepted_shares),8                "rejected_shares": int(rejected_shares),,                "fan_speed": int(fan_speed),"                "temp": int(temp),                "pool": pool,
            }C            logger.debug("claymore socket stats: {}".format(stats))            return stats        except Exception as e:            logger.warning(T                "could not handle sending or receiving from socket:" " {}".format(e)
            )B            return {"errors": "claymore http service unavailable"}    @staticmethod)    def get_xmr_stak_stats(xmr_stak_url):        try:B            stats = CoinmineRequests.get(xmr_stak_url, "api.json").            pool = stats["connection"]["pool"]9            uptime_in_sec = stats["connection"]["uptime"]4            # will report 0 if a single thread fails4            hashrate = stats["hashrate"]["total"][0]             if hashrate is None:                hashrate = 0=            accepted_shares = stats["results"]["shares_good"]P            rejected_shares = stats["results"]["shares_total"] - accepted_shares8            # None values come from failed gpus/threads,7            # we want to accurately report the hashrate$            # even if a thread fails8            hashrate_list = stats["hashrate"]["threads"]            # convert None to 0P            hashrate_list = [0 if i[0] is None else i[0] for i in hashrate_list]>            total_hashrate_threads = round(sum(hashrate_list))            return {2                "uptime": int(uptime_in_sec / 60),I                "hashrate": int(hashrate) or total_hashrate_threads or 0,/                "hashrate_list": hashrate_list,8                "accepted_shares": int(accepted_shares),8                "rejected_shares": int(rejected_shares),                "pool": pool,
            }        except Exception as e:L            logger.warning("could not return xmr-stak stats e={}".format(e))B            return {"errors": "xmr-stak http service unavailable"}    @staticmethod+    def get_nanominer_stats(nanominer_url):        try:            hashrate = 0            hashrate_list = []            accepted_shares = 0            rejected_shares = 0            uptime = 0@            stats = CoinmineRequests.get(nanominer_url, "stats")&            algs = stats["Algorithms"]            adapter = 0            for alg in algs:S                values = next(iter(alg.values()))  # gets the first value from dict/                algorithm = list(alg.keys())[0]>                hashrate += float(values["Total"]["Hashrate"])C                accepted_shares += int(values["Total"]["Accepted"])A                rejected_shares += int(values["Total"]["Denied"])0                pool = values.pop("CurrentPool")/                del values["ReconnectionCount"]#                del values["Total"]1                for key, value in values.items():7                    if key == "GPU {}".format(adapter):$                        adapter += 12                        if algorithm == "RandomX":>                            # pass on gpu hashrates on randomx$                            continueB                    hashrate_list.append(float(value["Hashrate"]))&            uptime = stats["WorkTime"]            return {%                "hashrate": hashrate,/                "hashrate_list": hashrate_list,!                "uptime": uptime,3                "accepted_shares": accepted_shares,3                "rejected_shares": rejected_shares,                "pool": pool,
            }        except Exception as e:M            logger.warning("could not return nanominer stats e={}".format(e))C            return {"errors": "nanominer http service unavailable"}    @staticmethodF    def get_teamredminer_stats(teamredminer_socket=("0.0.0.0", 4028)):        stats = {}        try:A            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)            logger.debug(>                "attempting to connect to teamredminer rpc on"1                " {}".format(teamredminer_socket)
            )*            s.connect(teamredminer_socket)9            logger.debug("connected to teamredminer rpc")            s.settimeout(60)!            s.sendall(b"summary")C            logger.debug("sent json for stats to teamredminer rpc")            data = s.recv(1024)?            logger.debug("received data from teamredminer rpc")'            string_data = data.decode().            list_data = string_data.split(",")=            stats["uptime"] = int(list_data[5].split("=")[1])I            hashrate = round(float(list_data[6].split("=")[1]) * 10e5, 3)(            stats["hashrate"] = hashrate/            stats["hashrate_list"] = [hashrate]G            stats["hardware_errors"] = int(list_data[14].split("=")[1])G            stats["accepted_shares"] = int(list_data[12].split("=")[1])G            stats["rejected_shares"] = int(list_data[13].split("=")[1])        except Exception as e:            logger.warning(Q                "could not handle sending or receiving from socket: {}".format(e)
            )        return stats    @staticmethod/    def get_hashtopolis_stats(hashtopolis_url):>        stats = CoinmineRequests.get(hashtopolis_url, "stats").        stats["hashrate"] = stats.pop("speed")4        stats["hashrate_list"] = [stats["hashrate"]]8        stats["accepted_shares"] = stats.pop("accepted")8        stats["uptime"] = stats.pop("uptime_in_seconds")        return stats    @staticmethod)    def get_lolminer_stats(lolminer_url):        stats = {}        try:@            data = CoinmineRequests.get(lolminer_url, "summary")            stats = {4                "uptime": data["Session"]["Uptime"],C                "hashrate": data["Session"]["Performance_Summary"],N                "hashrate_list": [gpu["Performance"] for gpu in data["GPUs"]],?                "accepted_shares": data["Session"]["Accepted"],?                "rejected_shares": data["Session"]["Submitted"].                - data["Session"]["Accepted"],8                "pool": data["Stratum"]["Current_Pool"],
            }        except Exception as e:H            logger.warning("could not get lolminer stats: {}".format(e))        return stats    @staticmethod*    def get_sixminer_stats(handshake_url):;        return MinerRequests.get_local_stats(handshake_url)    @staticmethod#    def get_xmrig_stats(xmrig_url):        stats = {}        try:?            data = CoinmineRequests.get(xmrig_url, "1/summary")            stats = {)                "uptime": data["uptime"],>                "hashrate": data["hashrate"]["total"][0] or 0,\                "hashrate_list": [thread[0] or 0 for thread in data["hashrate"]["threads"]],B                "accepted_shares": data["results"]["shares_good"],B                "rejected_shares": data["results"]["shares_total"]1                - data["results"]["shares_good"],3                "pool": data["connection"]["pool"],
            }        except Exception as e:E            logger.warning("could not get xmrig stats: {}".format(e))        return stats    @staticmethod    def get_local_stats(url):        stats = {}        try:5            data = CoinmineRequests.get(url, "stats")W            stats = {"hashrate": data["hashrate"], "hashrate_list": [data["hashrate"]]}        except Exception as e:E            logger.warning("could not get local stats: {}".format(e))        return stats    @staticmethod    def _is_hashing(hashrate):$        return bool(float(hashrate))5Б_–
	9L¤¤¤¤_†’w	х8:P                s.sendall(b'{"id":0,"jsonrpc":"2.0","method":"miner_getstat1"}')5Б_–	
1¤¤¤¤>+1v_†Џxх0?D        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:            logger.debug(:                "attempting to connect to claymore rpc on"-                " {}".format(claymore_socket)
            )&            s.connect(claymore_socket)5            logger.debug("connected to claymore rpc")            s.settimeout(60)L            s.sendall(b'{"id":0,"jsonrpc":"2.0","method":"miner_getstat2"}')?            logger.debug("sent json for stats to claymore rpc")            data = s.recv(1024);            logger.debug("received data from claymore rpc")#        string_data = data.decode()+        json_data = json.loads(string_data)5Б_–
1¤¤¤¤>'1v_†Џxх0?@    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:        logger.debug(6            "attempting to connect to claymore rpc on")            " {}".format(claymore_socket)	        )"        s.connect(claymore_socket)1        logger.debug("connected to claymore rpc")        s.settimeout(60)H        s.sendall(b'{"id":0,"jsonrpc":"2.0","method":"miner_getstat2"}');        logger.debug("sent json for stats to claymore rpc")        data = s.recv(1024)7        logger.debug("received data from claymore rpc")    string_data = data.decode()'    json_data = json.loads(string_data)5Б_–1¤¤¤¤1>V_†Џyх0?<with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:    logger.debug(2        "attempting to connect to claymore rpc on"%        " {}".format(claymore_socket)    )    s.connect(claymore_socket)-    logger.debug("connected to claymore rpc")    s.settimeout(60)D    s.sendall(b'{"id":0,"jsonrpc":"2.0","method":"miner_getstat2"}')7    logger.debug("sent json for stats to claymore rpc")    data = s.recv(1024)3    logger.debug("received data from claymore rpc")string_data = data.decode()#json_data = json.loads(string_data)5Б_–с¤¤¤¤^Вh™хрт
        stats = {	        }5Б_–с¤¤¤¤^ВhЂхстхтухту%                "accepted_shares": 0,$                "hashrate": 1041.74,:                "hashrate_list": [578.02, 231.77, 231.93],:                "pool": "xmr-us-east1.nanopool.org:14444",%                "rejected_shares": 0,                "uptime": 205,5Бз™
VimŸUnDoוa_ž®�±¢±7�פM²Š�¨F~ך�°כ�+W�¯DIŒJ            logger.warn("could not return grin miner stats", {"error": e})‡F,,,,\�ל5
_�$/����\��ץ#%ŒI            logger.debug("received miner status {}".format(miner_status))5_�$0����\��ץ#%Œ>            logger.debug("received miner status(miner_status))5_�$@����\��ץ#%Œ@            logger.debug("received miner status", miner_status))5_�&4����\��ץ%'ŒE            logger.error("failed to get miner status e={}".format(e))5_�&4����\��ץ%'Œ4            logger.error("failed to get miner status5_�&9����\��ץ%'Œ9            logger.error("failed to get miner status", ""5_�&?����\��ץ%'Œ@            logger.error("failed to get miner status", {"error"}5_�	&C����\��ץ%'ŒC            logger.error("failed to get miner status", {"error": e}5_�
	1:����\�מץ02Œ>                    "attempting to connect to claymore rpc on"5_�	
1:����\�ןץ02Œ:                    "attempting to connect to claymore rpc5_�
1:����\�סץ02Œ;                    "attempting to connect to claymore rpc"1                    " {}".format(claymore_socket)5_�
1;����\�עץ02‹Y                    "attempting to connect to claymore rpc" " {}".format(claymore_socket)5_�
1<����\�ףץ02‹L                    "attempting to connect to claymore rpc"(claymore_socket)5_�
1=����\�רץ02‹N                    "attempting to connect to claymore rpc", "claymore_socket)5_�1?����\�שץ02‹P                    "attempting to connect to claymore rpc", {}"claymore_socket)5_�1N����\��ץ02‹O                    "attempting to connect to claymore rpc", {"claymore_socket)ץ12‹5_�1a����\�žץ02‹b                    "attempting to connect to claymore rpc", {"claymore_socket": claymore_socket))5_�1b����\�žץ02‹b                    "attempting to connect to claymore rpc", {"claymore_socket": claymore_socket})5_�1`����\�žץ‹
import socketimport json from utils import CoinmineLogger+from utils.requests import CoinmineRequests!logger = CoinmineLogger(__name__)class MinerRequests:    @staticmethodN    def get_miner_status(coin, claymore_socket, xmr_stak_url, grin_miner_url):        # we assume not mining        miner_status = {            "uptime": 0,            "hashrate": 0,!            "hashrate_list": [0],!            "accepted_shares": 0,!            "rejected_shares": 0,            "fan_speed": 0,            "temp": 0,            "pool": "",            "errors": [],	        }        try:            miners = {V                "ethereum": lambda: MinerRequests.get_claymore_stats(claymore_socket),S                "zcash": lambda: MinerRequests.get_claymore_stats(claymore_socket),Q                "monero": lambda: MinerRequests.get_xmr_stak_stats(xmr_stak_url),S                "grin": lambda: MinerRequests.get_grin_miner_stats(grin_miner_url),K                None: lambda: {"errors": "missing coin value from config"},
            }=            miner_status = {**miner_status, **miners[coin]()}?            logger.debug("received miner status", miner_status)        except Exception as e:D            logger.error("failed to get miner status", {"error": e})X        miner_status["mining"] = MinerRequests._is_hashing(miner_status.get("hashrate"))        return miner_status    @staticmethod,    def get_claymore_stats(claymore_socket):        try:H            with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:                logger.debug(a                    "attempting to connect to claymore rpc", {"claymore_socket": claymore_socket}                )*                s.connect(claymore_socket)9                logger.debug("connected to claymore rpc")                 s.settimeout(60)P                s.sendall(b'{"id":0,"jsonrpc":"2.0","method":"miner_getstat1"}')C                logger.debug("sent json for stats to claymore rpc")#                data = s.recv(1024)?                logger.debug("received data from claymore rpc")'            string_data = data.decode()/            json_data = json.loads(string_data)-            result_list = json_data["result"]*            uptime_in_min = result_list[1]:            accepted_shares = result_list[2].split(";")[1]:            rejected_shares = result_list[2].split(";")[2]%            hashrate = result_list[3]            # multigpu            if ";" in hashrate:E                hashrate_list = list(map(float, hashrate.split(";")))-                hashrate = sum(hashrate_list)            else:1                hashrate_list = [float(hashrate)]4            fan_speed = result_list[6].split(";")[1]/            temp = result_list[6].split(";")[0]!            pool = result_list[7]            stats = {4                "uptime": int(float(uptime_in_min)),*                "hashrate": int(hashrate),/                "hashrate_list": hashrate_list,8                "accepted_shares": int(accepted_shares),8                "rejected_shares": int(rejected_shares),,                "fan_speed": int(fan_speed),"                "temp": int(temp),                "pool": pool,
            }C            logger.debug("claymore socket stats: {}".format(stats))            return stats        except Exception as e:            logger.warn(T                "could not handle sending or receiving from socket:" " {}".format(e)
            )B            return {"errors": "claymore http service unavailable"}    @staticmethod)    def get_xmr_stak_stats(xmr_stak_url):        try:B            stats = CoinmineRequests.get(xmr_stak_url, "api.json").            pool = stats["connection"]["pool"]9            uptime_in_sec = stats["connection"]["uptime"]4            # will report 0 if a single thread fails4            hashrate = stats["hashrate"]["total"][0]             if hashrate is None:                hashrate = 0=            accepted_shares = stats["results"]["shares_good"]P            rejected_shares = stats["results"]["shares_total"] - accepted_shares8            # None values come from failed gpus/threads,7            # we want to accurately report the hashrate$            # even if a thread fails8            hashrate_list = stats["hashrate"]["threads"]            # convert None to 0P            hashrate_list = [0 if i[0] is None else i[0] for i in hashrate_list]>            total_hashrate_threads = round(sum(hashrate_list))            return {2                "uptime": int(uptime_in_sec / 60),D                "hashrate": int(hashrate) or total_hashrate_threads,/                "hashrate_list": hashrate_list,8                "accepted_shares": int(accepted_shares),8                "rejected_shares": int(rejected_shares),                "pool": pool,
            }        except Exception as e:I            logger.warn("could not return xmr-stak stats e={}".format(e))B            return {"errors": "xmr-stak http service unavailable"}-    def get_grin_miner_stats(grin_miner_url):        try:A            stats = CoinmineRequests.get(grin_miner_url, "stats")5            hashrate = stats["results"]["graph_rate"]F            return {"hashrate": hashrate, "hashrate_list": [hashrate]}        except Exception as e:K            logger.warn("could not return grin miner stats e={}".format(e))D            return {"errors": "grin miner http service unavailable"}    @staticmethod    def _is_hashing(hashrate):)        return bool(int(float(hashrate)))5_�U#����\�žץTVŒC            logger.debug("claymore socket stats: {}".format(stats))5_�U#����\�žץTVŒC            logger.debug("claymore socket stats: {}".format(stats))5_�U����\�žץTVŒC            logger.debug("claymore socket stats: {}".format(stats))5_�U9����\�ž ץTVŒL            logger.debug("recieved claymore socket stats: {}".format(stats))5_�U9����\�ž!ץTVŒL            logger.debug("recieved claymore socket stats" {}".format(stats))5_�U9����\�ž"ץTVŒ9            logger.debug("recieved claymore socket stats"5_�YB����\�ž.ץXZŒT                "could not handle sending or receiving from socket:" " {}".format(e)5_�YB����\�ž0ץXZŒB                "could not handle sending or receiving from socket5_�YM����\�ž4ץXZŒN                "could not handle sending or receiving from socket", {"error"}5_� ~7����\�žEץ}ŒI            logger.warn("could not return xmr-stak stats e={}".format(e))ץ~Œ5_�! ~G����\�žFץ}ŒX            logger.warn("could not return xmr-stak stats", {"error": e} e={}".format(e))5_� #!~G����\�žJץ}ŒG            logger.warn("could not return xmr-stak stats", {"error": e}5_�!$"#‡9����\�žUץ†ˆŒK            logger.warn("could not return grin miner stats e={}".format(e))ץ‡ˆŒ5_�#%$‡J����\�žV	ץ†ˆŒ[            logger.warn("could not return grin miner stats", {"error": e}) e={}".format(e))5_�$&%&@����\�ל'ץ%'ŒD            logger.error("failed to get miner status", {"error": e})ץ&'Œ5_�%'&&F����\�ל(
ץ%'ŒH            logger.error("failed to get miner status", {"error": str(e})5_�&('YN����\�ל+ץXZŒQ                "could not handle sending or receiving from socket", {"error": e}ץYZŒ5_�')(YT����\�ל,ץXZŒU                "could not handle sending or receiving from socket", {"error": str(e}5_�(*)~D����\�ל/ץ}ŒH            logger.warn("could not return xmr-stak stats", {"error": e})ץ~Œ5_�)+*~J����\�ל0ץ}ŒL            logger.warn("could not return xmr-stak stats", {"error": str(e})5_�*,+‡F����\�ל3ץ†ˆŒJ            logger.warn("could not return grin miner stats", {"error": e})ץ‡ˆŒ5_�+,‡L����\�ל4
ץ†ˆŒN            logger.warn("could not return grin miner stats", {"error": str(e})5_�!#"~8����\�žQץ}Œ8            logger.warn("could not return xmr-stak stats5_�YB����\�žAץXZŒB                "could not handle sending or receiving from socket5_�1?����\�תץ02‹?                    "attempting to connect to claymore rpc", {"5ח×