<commit_before>import logging
import serial
import signal
import sys
from functools import partial

from isac import IsacNode, IsacValue
from isac.tools import green

logger = logging.getLogger(__name__)

logging.basicConfig(level=logging.INFO)

class BadChecksum(Exception):
    pass

def _read_trame(trame):
    trame = trame.strip('\r\n')

    if not _checksum(trame):
        raise BadChecksum(trame)

    # Separator can either be a space or a tab
    sep = trame[-2]
    first_sep_i = trame.index(sep)

    tag = trame[:first_sep_i]
    data = trame[first_sep_i+1:-2]

    return tag, data

def _checksum(trame):
    c = ord(trame[-1])

    sum_ = sum(map(ord, trame[:-2]))
    if ((sum_ & 0x3F) + 0x20) == c:
        return True

    # Try with the last separator (new norm)
    sum_ += ord(trame[-2])
    if ((sum_ & 0x3F) + 0x20) == c:
        return True

    return False

class AlidronTIC(object):
    def __init__(self, port):
        self.isac_node = IsacNode('alidron-tic')
        green.signal(signal.SIGTERM, partial(self._sigterm_handler))
        green.signal(signal.SIGINT, partial(self._sigterm_handler))

        self.ser = serial.Serial(
            port=port,
            baudrate=1200,
            bytesize=serial.SEVENBITS,
            parity=serial.PARITY_EVEN,
            stopbits=serial.STOPBITS_ONE,
            timeout=1
        )

        self.signals = {}

    def start(self):
        green.spawn(self.run)

    def serve_forever(self):
        self.start()
        try:
            while True:
                green.sleep(1)
        except (KeyboardInterrupt, SystemExit):
            logger.info('Stopping')
            self.stop()

    def stop(self):
        self.running = False
        self.isac_node.shutdown()
        green.sleep(2)

    def _sigterm_handler(self):
        logger.info('Received SIGTERM signal, exiting')
        self.stop()
        logger.info('Exiting')
        sys.exit(0)

    def run(self):
        self.running = True
        while self.running:
            try:
                try:
                    tag, data = _read_trame(self.ser.readline())
                except BadChecksum:
                    continue

                logger.debug('Read %s: %s', tag, data)
                try:
                    signal = self.signals[tag]
                except KeyError:
                    logger.info('Creating ISAC value for %s', tag)
                    metadata = {
                        'ts_precision': 's',
                        'smoothing': True
                    }
                    signal = IsacValue(
                        self.isac_node,
                        'tic://alidron-tic/%s' % tag,
                        static_tags={'location': 'entrance.switchboard'},
                        metadata=metadata,
                        survey_last_value=False,
                        survey_static_tags=False
                    )
                    self.signals[tag] = signal

                try:
                    signal.value = int(data)<commit_msg>More resilient publishing of tags.<commit_after>import logging
import serial
import signal
import sys
from functools import partial

from isac import IsacNode, IsacValue
from isac.tools import green

logger = logging.getLogger(__name__)

logging.basicConfig(level=logging.INFO)

class BadChecksum(Exception):
    pass

def _read_trame(trame):
    trame = trame.strip('\r\n')

    if not _checksum(trame):
        raise BadChecksum(trame)

    # Separator can either be a space or a tab
    sep = trame[-2]
    first_sep_i = trame.index(sep)

    tag = trame[:first_sep_i]
    data = trame[first_sep_i+1:-2]

    return tag, data

def _checksum(trame):
    c = ord(trame[-1])

    sum_ = sum(map(ord, trame[:-2]))
    if ((sum_ & 0x3F) + 0x20) == c:
        return True

    # Try with the last separator (new norm)
    sum_ += ord(trame[-2])
    if ((sum_ & 0x3F) + 0x20) == c:
        return True

    return False

class AlidronTIC(object):

    ALLOWED_TAGS = ['ADCO', 'BASE', 'IINST', 'IMAX', 'ISOUSC', 'OPTARIF', 'PAPP', 'PTEC']

    def __init__(self, port):
        self.isac_node = IsacNode('alidron-tic')
        green.signal(signal.SIGTERM, partial(self._sigterm_handler))
        green.signal(signal.SIGINT, partial(self._sigterm_handler))

        self.ser = serial.Serial(
            port=port,
            baudrate=1200,
            bytesize=serial.SEVENBITS,
            parity=serial.PARITY_EVEN,
            stopbits=serial.STOPBITS_ONE,
            timeout=1
        )

        self.signals = {}

    def start(self):
        green.spawn(self.run)

    def serve_forever(self):
        self.start()
        try:
            while True:
                green.sleep(1)
        except (KeyboardInterrupt, SystemExit):
            logger.info('Stopping')
            self.stop()

    def stop(self):
        self.running = False
        self.isac_node.shutdown()
        green.sleep(2)

    def _sigterm_handler(self):
        logger.info('Received SIGTERM signal, exiting')
        self.stop()
        logger.info('Exiting')
        sys.exit(0)

    def run(self):
        self.running = True
        while self.running:
            try:
                try:
                    tag, data = _read_trame(self.ser.readline())
                except BadChecksum:
                    continue

                logger.debug('Read %s: %s', tag, data)
                
                if tag not in self.ALLOWED_TAGS:
                    logger.warning('Discarding %s: %s', tag, data)
                    continue
                
                try:
                    signal = self.signals[tag]
                except KeyError:
                    logger.info('Creating ISAC value for %s', tag)
                    metadata = {
                        'ts_precision': 's',
                        'smoothing': True
                    }
                    signal = IsacValue(
                        self.isac_node,
                        'tic://alidron-tic/%s' % tag,
                        static_tags={'location': 'entrance.switchboard'},
                        metadata=metadata,
                        survey_last_value=False,
                        survey_static_tags=False
                    )
                    self.signals[tag] = signal

                try:
                    signal.value = int(data)
{'fraction_non_alphanumeric': 0.10241530740276035, 'fraction_numerical': 0.0075282308657465494, 'mean_word_length': 1.549780087964814, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3570983', 'n_tokens_mistral': 1956, 'n_tokens_neox': 1847, 'n_words': 399}