package com.knutejohnson.pi.thermometer;

import java.io.*;
import java.net.*;
import java.nio.charset.*;
import java.nio.file.*;
import java.util.*;
import java.util.regex.*;

/**
 * TemperatureSenderDS18B20 is a complimentary program to Thermometer to
 * transmit temperature data from a Pi with a DS18B20 device attached.
 * TemperatureSenderDS18B20 sends the data via multicast packet to the
 * Thermometer program.  TemperatureSenderDS18B20 is designed to be run
 * repeatedly by cron but may be run from the command line for testing.
 * The program has three command line options that are required, the serial
 * number of the the DS18B20 device (the leading zeros may be omitted),
 * the location/description to be displayed with the temperature on the
 * Thermometer program and the channel number.  Valid channel numbers are 0
 * through 5.  Spaces may be included in the location by enclosing the option
 * with quoes (ie java -jar TemperatureSenderDS18B20.jar 6774267 "Spare Room"
 * 2).
 *
 * @version 0.10 - 4 January 2019
 * @author  Knute Johnson
 */

public class TemperatureSenderDS18B20 {
    /** Program version */
    private static final String VERSION = "0.10";

    /** Program date */
    private static final String DATE = "4 January 2019";

    /** Destination port for multicast data packets */
    private static final int PORT = 56789;

    /** Multicast IP address */
    private static final String IPADDR = "239.0.0.123";

    /**
     * Program entry point, checks for valid command line arguments, reads the
     * temperature data from the DS18B20 device and sends that data to the
     * Thermometer program.
     *
     * @param   args    command line arguments (see above)
     */
    public static void main(String... args) {
        if (args.length == 3) {
            try {
                // zero pad the serial number string
                String serialNumStr =
                 String.format("%012d",Integer.parseInt(args[0]));
                String location = args[1];
                int channel = Integer.parseInt(args[2]);
                if (channel < 0 || channel > 5)
                    throw new NumberFormatException("channel not 0-5");

                Path path = FileSystems.getDefault().getPath(String.format(
                 "/sys/bus/w1/devices/28-%s/w1_slave",serialNumStr));
                try {
                    String[] arr = Files.lines(path).toArray(String[]::new);
                    if (arr.length == 2 && arr[0].contains("YES")) {
                        // pattern to search for temperature
                        Pattern pattern = Pattern.compile("t=(\\d+)");
                        Matcher m = pattern.matcher(arr[1]);
                        // if the temperature is in the second line of data
                        // pack the location, channel number and temperature
                        // into a UTF-8 string and send it twice with a half
                        // second paus because sometimes the packets get lost
                        if (m.find()) {
                            try (MulticastSocket socket = new MulticastSocket(
                             PORT)) {
                                String str = String.format("%s,%d,%s",
                                 location,channel,m.group(1));
                                DatagramPacket packet = new DatagramPacket(
                                 str.getBytes(StandardCharsets.UTF_8),
                                 str.length(),InetAddress.getByName(IPADDR),
                                 PORT);
                                // send the data, wait 1/4 sec and send again
                                socket.send(packet);
                                Thread.sleep(250);
                                socket.send(packet);
                             }
                        } else {
                            System.out.println("temp pattern not matched");
                        }
                    } else {
                        System.out.println("input data error");
                    }
                } catch (IOException|InterruptedException ex) {
                    ex.printStackTrace();
                }
            } catch (NumberFormatException nfe) {
                nfe.printStackTrace();
            }
        } else {
            System.out.println("Usage: java -jar TemperatureSenderDS18B20.jar" +
             " serialNumber location channel(0-5)");
        }
    }
}