<commit_before>package nl.homesensors.sensortag;

import static net.sf.expectit.filter.Filters.removeColors;
import static net.sf.expectit.filter.Filters.removeNonPrintable;
import static net.sf.expectit.matcher.Matchers.contains;
import static net.sf.expectit.matcher.Matchers.eof;
import static net.sf.expectit.matcher.Matchers.regexp;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import net.sf.expectit.Expect;
import net.sf.expectit.ExpectBuilder;
import net.sf.expectit.Result;
import nl.homesensors.sensortag.publisher.ClimatePublisher;

/**
 * Connects to a Texas Instruments Sensortag over Bluetooth low energy to periodically
 * obtain the actual temperature and humidity.
 *
 * The obtained values will be published to each {@link ClimatePublisher}.
 *
 * Dependencies:
 * blueZ (gattool and hcitool) needs to be installed on the host OS (see http://www.bluez.org/).
 */
@Component
public class SensorTagReader {

    private static final Logger LOG = LoggerFactory.getLogger(SensorTagReader.class);

    private static final int NR_OF_SECONDS_TO_WAIT_BEFORE_ATTEMPT_RECONNECT = 10;

    private final List<ClimatePublisher> climatePublishers;

    @Value("${sensortag.bluetooth.address:#{null}}")
    private String sensortagBluetoothAddress;

    @Value("${sensortag.probetime.seconds:#{null}}")
    private Integer sensortagProbeTimeInSeconds;

    @Value("${sensortag-klimaat-sensorcode:#{null}}")
    private String sensorCode;

    private final Thermometer thermometer = new Thermometer();
    private final Hygrometer hygrometer = new Hygrometer();

    public SensorTagReader(final List<ClimatePublisher> climatePublishers) {
        this.climatePublishers = climatePublishers;
    }

    @Async
    public void run() throws Exception {

        if (sensortagBluetoothAddress == null || sensortagProbeTimeInSeconds == null || sensorCode == null) {
            LOG.warn("Not started SensorTagReader, because the configuration for it is not defined.");
        } else {
            LOG.info("Start SensorTagReader");

            while (true) {
                try {
                    connectAndListenForSensorValues();
                } catch (final SensortagException e) {
                    LOG.error("Error occurred: {}", e.getMessage());
                    LOG.error("Trying to reconnect in 10 seconds...");
                    Thread.sleep(NR_OF_SECONDS_TO_WAIT_BEFORE_ATTEMPT_RECONNECT * 1000);
                }
            }
        }
    }

    private void connectAndListenForSensorValues() throws IOException, InterruptedException, SensortagException {
        final Process process = createShellProcess();
        final Expect expect = getExpectBuilder(process).build();

        killAllGatttools(expect);

        try {
            startInteractiveGattool(expect);
            connect(expect);
            setConnectionParameters();

            /*
             * From the TI SensorTag Guide:
             *
             * The most power efficient way to obtain measurements for a sensor is to
             * 1. Enable notification
             * 2. Enable Sensor<commit_msg>Sonar<commit_after>package nl.homesensors.sensortag;

import static net.sf.expectit.filter.Filters.removeColors;
import static net.sf.expectit.filter.Filters.removeNonPrintable;
import static net.sf.expectit.matcher.Matchers.contains;
import static net.sf.expectit.matcher.Matchers.eof;
import static net.sf.expectit.matcher.Matchers.regexp;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import net.sf.expectit.Expect;
import net.sf.expectit.ExpectBuilder;
import net.sf.expectit.Result;
import nl.homesensors.sensortag.publisher.ClimatePublisher;

/**
 * Connects to a Texas Instruments Sensortag over Bluetooth low energy to periodically
 * obtain the actual temperature and humidity.
 *
 * The obtained values will be published to each {@link ClimatePublisher}.
 *
 * Dependencies:
 * blueZ (gattool and hcitool) needs to be installed on the host OS (see http://www.bluez.org/).
 */
@Component
public class SensorTagReader {

    private static final Logger LOG = LoggerFactory.getLogger(SensorTagReader.class);

    private static final int NR_OF_SECONDS_TO_WAIT_BEFORE_ATTEMPT_RECONNECT = 10;

    private final List<ClimatePublisher> climatePublishers;

    @Value("${sensortag.bluetooth.address:#{null}}")
    private String sensortagBluetoothAddress;

    @Value("${sensortag.probetime.seconds:#{null}}")
    private Integer sensortagProbeTimeInSeconds;

    @Value("${sensortag-klimaat-sensorcode:#{null}}")
    private String sensorCode;

    private final Thermometer thermometer = new Thermometer();
    private final Hygrometer hygrometer = new Hygrometer();

    public SensorTagReader(final List<ClimatePublisher> climatePublishers) {
        this.climatePublishers = climatePublishers;
    }

    @Async
    public void run() throws Exception {

        if (sensortagBluetoothAddress == null || sensortagProbeTimeInSeconds == null || sensorCode == null) {
            LOG.warn("Not started SensorTagReader, because the configuration for it is not defined.");
        } else {
            LOG.info("Start SensorTagReader");

            while (true) {
                try {
                    connectAndListenForSensorValues();
                } catch (final SensortagException e) {
                    LOG.error("Error occurred: {}. Trying to reconnect in {} seconds...", e.getMessage(), NR_OF_SECONDS_TO_WAIT_BEFORE_ATTEMPT_RECONNECT);
                    Thread.sleep(NR_OF_SECONDS_TO_WAIT_BEFORE_ATTEMPT_RECONNECT * 1000);
                }
            }
        }
    }

    private void connectAndListenForSensorValues() throws IOException, InterruptedException, SensortagException {
        final Process process = createShellProcess();
        final Expect expect = getExpectBuilder(process).build();

        killAllGatttools(expect);

        try {
            startInteractiveGattool(expect);
            connect(expect);
            setConnectionParameters();

            /*
             * From the TI SensorTag Guide:
             *
             * The most power efficient way to obtain measurements for a sensor is to
             * 1. Enable notification
             * 2. Enable Sensor
{'fraction_non_alphanumeric': 0.08901375129380452, 'fraction_numerical': 0.0032529942333284047, 'mean_word_length': 3.2012422360248447, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '7389714', 'n_tokens_mistral': 1942, 'n_tokens_neox': 1842, 'n_words': 447}