#!/usr/bin/php
<?php
#
# Usage: mqtt-sub-handler [-d]
#
# This service receives messages via MQTT subscriptions from Nyquist appliances
# that provide device status.
#
# (C) Copyright 2022, Bogen Communications, Inc. All rights reserved.
#
#

$debug = TRUE;

# Do not run this service if we are not using 3.0 firmware or above
$VER=file_get_contents("/opt/bogen/appliance/VERSION.config");
if( substr($VER, 0, 1) < 3 ) {
	exit(0);
}

$MAC_ADDR=file_get_contents("/sys/class/net/eth0/address");
$MAC_ADDR=trim(str_replace(':','',$MAC_ADDR));
$PART_NUM=trim(file_get_contents('/sys/devices/platform/bone_capemgr/slot-0/part-number'));
if ( $PART_NUM == "nq-asb" ) {
	$TOPIC_LIST="-t 'checkin' -t 'checkin_exclude'";
	if ($debug) echo "ASB....using topics $TOPIC_LIST\n";
}
else if ( strncmp($PART_NUM, "nq-a", 4) === 0 ) {
	$TOPIC_LIST="-t 'sm_amp'";
	if ($debug) echo "Nyquist Amplifier....using topics $TOPIC_LIST\n";
}
else {
	if ($debug) echo "The $PART_NUM appliance is not using MQTT....exiting \n";
	#clean exit signal should keep the service from starting again
	exit(0);
}

$checkin_file = '/etc/nyquist/check-in';
$checkin_exclude_file = '/etc/nyquist/checkin_exclude';
$sm_file = '/etc/nyquist/sm_info';
$sm_ramp_cmd = '/usr/local/bin/sm_ramp';

$myPid = getmypid();
exec("/usr/local/bin/find_tftp_server 2>&1", $server_ip);

$cmd_options = getopt("d:");

foreach (array_keys($cmd_options) as $opt)
	switch ($opt) {
		case 'd':
			$debug = TRUE;
			echo "Activing DEBUG mode\n";
			break;
#		case 'f':
#			$rsyslogFacility = $cmd_options['f'];
#			break;
}

#
# We want to log an alert to syslog upon exit
#
#register_shutdown_function('logExit');

#
# Handle signals
#
pcntl_signal(SIGHUP,  "cleanExit");
pcntl_signal(SIGQUIT, "cleanExit");
pcntl_signal(SIGSEGV, "cleanExit");
pcntl_signal(SIGTERM, "cleanExit");
pcntl_signal(SIGUSR1, SIG_IGN);
pcntl_signal(SIGUSR2, "cleanExit");

#
# Turn off error reporting if not in debug mode because errors have nowhere
# to go.
#
if ($debug == FALSE) {
        error_reporting(0);
}

$MQTT_DIR="/etc/mosquitto";
$MQTT_PWD_FILE="$MQTT_DIR/mqtt_pwd";
$MQTT_UNAME="nyquist";

$MSG_RECEIVED=false;
$mqtt_status_file="/etc/nyquist/mqtt_status";
if(file_exists($mqtt_status_file)) {
	exec("unlink $mqtt_status_file");
}




#
# Possible topics from appliances:
#
# checkin <extension>
# protection_mode <Device-MAC-Address>
#

while (1) 
{
	if(!file_exists($MQTT_PWD_FILE)) {
		$MQTT_PWD="NyCtrlPwdDefault2022";
		file_put_contents($MQTT_PWD_FILE, $MQTT_PWD);
	}
	else {
		$MQTT_PWD=trim(file_get_contents($MQTT_PWD_FILE));
	}
	#echo "/usr/local/bin/mosquitto_sub -h $server_ip[0] -u $MQTT_UNAME -P $MQTT_PWD $TOPIC_LIST --cafile /etc/mosquitto/bogenCA.crt";
	if (($p_handle = popen("/usr/local/bin/mosquitto_sub -h $server_ip[0] -u $MQTT_UNAME -P $MQTT_PWD $TOPIC_LIST --cafile /etc/mosquitto/bogenCA.crt -q 1 -v", "r")) === false)
	{
		echo "nyquist-status: popen error, exiting\n";
		exit(1);
	}
	
	if ($debug) {
		echo "Listening for messages...\n";
	}
	
	$fh = fopen($mqtt_status_file, 'w');
	if($fh) {
		fwrite($fh, print_r("1",TRUE));
		fflush($fh);
		exec("sync");
	}
	fclose($fh);

	# Clear out the buffer containing old messages
	$msg_buffer = fgets($p_handle, 4096);
	#if ($debug) echo "JUNK: $msg_buffer";

	while (!feof($p_handle))
	{

		if (($msg_buffer = fgets($p_handle, 4096)) !== false)
		{
			if ($debug) echo "$msg_buffer";
			#$msg_buffer = strtok($msg_buffer, ' ');
			$msg_parts = explode(' ', $msg_buffer);
			$msg_topic = $msg_parts[0];
			if($MSG_RECEIVED == true) {
				call_user_func($msg_topic, $msg_buffer);
			}
			else {
				$MSG_RECEIVED = true;
			}
		}
	}

	echo "Sleeping\n";
	$sleepTime=1;
	while($sleepTime <= 60) {
		#echo "Sleep $sleepTime\n";
		sleep(1);
		$sleepTime++;
	}
}

echo "Exit with failure\n";
exit(1);

###############
# END OF MAIN #
###############

function checkin($msg_buffer)
{	
	global $debug;
	if ($debug) {
		$microDate = 'Checkin received: ' . date_create_from_format( 'U.u', number_format(microtime(true), 6, '.', ''))->setTimezone((new \DateTimeZone('America/New_York')))->format('ymd H:i:s.u e'); 
		echo "$microDate\n";
	}
	global $checkin_file;
	global $checkin_exclude_file;
	$msg_parts = explode(' ', $msg_buffer);
	$checkin_cmd = trim($msg_parts[1]);
	if ($debug) echo "  Command: $checkin_cmd\n";
	
	if($checkin_cmd == 'start') {
		exec("touch $checkin_file");
		exec("sync");
	}
	else if($checkin_cmd == 'stop') {
		if(file_exists($checkin_file)) {
			exec("unlink $checkin_file");
		}
		if(file_exists($checkin_exclude_file)) {
			exec("unlink $checkin_exclude_file");
		}
		exec("sync");
	}
}

function checkin_exclude($msg_buffer)
{
	global $debug;
	if ($debug) {
		$microDate = 'Checkin_exclude received: ' . date_create_from_format( 'U.u', number_format(microtime(true), 6, '.', ''))->setTimezone((new \DateTimeZone('America/New_York')))->format('ymd H:i:s.u e'); 
		echo "$microDate\n";
	}
	global $checkin_exclude_file;
	$msg_parts = explode(' ', $msg_buffer);
	$checkin_exclude_cmd = trim($msg_parts[1]);
	if($checkin_exclude_cmd != '0') {
		if ($debug) echo "  Command: $checkin_exclude_cmd\n";
		$fh = fopen($checkin_exclude_file, 'w');
		if($fh) {
			fwrite($fh, print_r($checkin_exclude_cmd,TRUE));
			fflush($fh);
			exec("sync");
		}
		fclose($fh);
	}
}

function sm_amp($msg_buffer)
{
	global $debug;
	global $MAC_ADDR;
	global $sm_file;
	global $sm_ramp_cmd;
	global $server_ip;
	$msg_parts = explode(' ', $msg_buffer);

	$numArgs = sizeof($msg_parts);

	if($numArgs == 3) {
		$sm_amp_mac = trim($msg_parts[1]);
		$sm_amp_cmd = trim($msg_parts[2]);
	}
	else {
		$sm_amp_mac = trim($msg_parts[1]);
		$sm_amp_port = trim($msg_parts[2]);
		$sm_amp_cmd = trim($msg_parts[3]);
	}

	$RAMP_CRON_CMD="/usr/bin/php $sm_ramp_cmd $sm_amp_port";
	$RAMP_CRON_JOB="0 0 * * * $RAMP_CRON_CMD";
	

	$sm_volume_file = '/etc/nyquist/sm_volume';
	$sm_port_ramp_file = '/etc/nyquist/sm_ramp';

	if(strcmp($sm_amp_mac, $MAC_ADDR) !== 0) {
		if ($debug) echo "  Bad MAC\n";
		return;
	}

	if($numArgs == 3) {
		if($sm_amp_cmd == 'reboot') {
			exec("/usr/local/bin/reboot_now");
		}
	}

	#if ($debug) echo "  Port: $sm_amp_port\n";
	
	$port_file = $sm_file . "_" . $sm_amp_port;
	$port_vol_file = $sm_volume_file . "_" . $sm_amp_port;
	$port_ramp_file = $sm_port_ramp_file . "_" . $sm_amp_port;
	#if ($debug) echo "  Port File: $port_file\n";
	#if ($debug) echo "  Ramp File: $port_ramp_file\n";
	if($sm_amp_cmd == 'adjust-volume') {
		$sm_amp_volume = trim($msg_parts[4]);
		if ($debug) echo "  Adjust Volume to $sm_amp_volume\n";
		$smPipe = fopen("/usr/local/bin/extSMChannel_$sm_amp_port", "w");
		if ($debug) echo "  Writing to extSMChannel_$sm_amp_port: $sm_amp_cmd\n";
		fwrite($smPipe, "$sm_amp_cmd $sm_amp_volume");
		fclose($smPipe); 
		#$fh = fopen($port_vol_file, 'w');
		#if($fh) {
		#	fwrite($fh, print_r("$sm_amp_volume",TRUE));
		#	fflush($fh);
		#	exec("sync");
		#}
		#fclose($fh);

	}
	else if($sm_amp_cmd == 'disable-sm') {
		if ($debug) echo "  Disable Sound Masking\n";
		$smPipe = fopen("/usr/local/bin/extSMChannel_$sm_amp_port", "w");
		if ($debug) echo "  Writing to extSMChannel_$sm_amp_port: $sm_amp_cmd\n";
		fwrite($smPipe, "$sm_amp_cmd");
		fclose($smPipe); 

		// Remove ramp file so we don't start ramping again while disabled
		if(file_exists($port_ramp_file)) {
			exec("unlink $port_ramp_file");
			exec("sync");
		}

		# Remove the cron job
		$CRON_UPDATE_CMD = "crontab -l | grep -v \\\"$RAMP_CRON_CMD\\\" | crontab -";
		shell_exec("bash -c \"$CRON_UPDATE_CMD\"");

		if ($debug) echo "  $RAMP_CRON_CMD $sm_amp_cmd\n";
		shell_exec("bash -c \"$RAMP_CRON_CMD $sm_amp_cmd\"");
	}
	else if($sm_amp_cmd == 'enable-sm') {
		$sm_amp_speaker_preset = trim($msg_parts[4]);
		if ($debug) echo "  Enable Sound Masking with speaker preset $sm_amp_speaker_preset\n";
		$smPipe = fopen("/usr/local/bin/extSMChannel_$sm_amp_port", "w");
		if ($debug) echo "  Writing to extSMChannel_$sm_amp_port: $sm_amp_cmd\n";
		fwrite($smPipe, "$sm_amp_cmd");
		fclose($smPipe); 
	}
	else if($sm_amp_cmd == 'pause') {
		$smPipe = fopen("/usr/local/bin/extSMChannel_$sm_amp_port", "w");
		if ($debug) echo "  Writing to extSMChannel_$sm_amp_port: $sm_amp_cmd\n";
		fwrite($smPipe, "$sm_amp_cmd");
		fclose($smPipe); 
		if ($debug) echo "  Pause Sound Masking for port $sm_amp_port\n";
	}
	else if($sm_amp_cmd == 'resume') {
		$smPipe = fopen("/usr/local/bin/extSMChannel_$sm_amp_port", "w");
		if ($debug) echo "  Writing to extSMChannel_$sm_amp_port: $sm_amp_cmd\n";
		fwrite($smPipe, "$sm_amp_cmd");
		fclose($smPipe); 
		#$sm_amp_speaker_preset = trim($msg_parts[4]);
		if ($debug) echo "  Resume Sound Masking for port $sm_amp_port\n";
	}
	else if($sm_amp_cmd == 'scheduled-ramp') {
		if ($debug) echo "  Scheduled ramp for port $sm_amp_port\n";
		$smPipe = fopen("/usr/local/bin/extSMChannel_$sm_amp_port", "w");
		$sm_zone_num = trim($msg_parts[4]);
		$sm_ramp_dir = trim($msg_parts[5]);
		$sm_ramp_duration = trim($msg_parts[6]);
		$sm_ramp_value = trim($msg_parts[7]);

		if ($debug) echo "      Zone: $sm_zone_num\n";
		if ($debug) echo "      Dir: $sm_ramp_dir\n";
		if ($debug) echo "      Dur: $sm_ramp_duration\n";
		if ($debug) echo "      Val: $sm_ramp_value\n";
		if ($debug) echo "      Server IP: $server_ip[0]\n";

		fwrite($smPipe, "$sm_amp_cmd $sm_ramp_dir $sm_ramp_duration $sm_ramp_value");
		fclose($smPipe); 
	}
	else if($sm_amp_cmd == 'start-ramp') {
		if ($debug) echo "  Start Ramp\n";
		$sm_zone_num = trim($msg_parts[4]);
		$sm_ramp_days = trim($msg_parts[5]);
		if ($debug) echo "      Zone: $sm_zone_num\n";
		if ($debug) echo "      Days: $sm_ramp_days\n";
		if ($debug) echo "      Server IP: $server_ip[0]\n";
		
		$fh = fopen($port_ramp_file, 'w');
		if($fh) {
			#<Ramp Days> <Ramp Days> <Zone> <Port> <server_ip_address>
			fwrite($fh, print_r("$sm_ramp_days $sm_ramp_days $sm_zone_num $sm_amp_port $server_ip[0]",TRUE));
			fflush($fh);
			exec("sync");
		}
		fclose($fh);

		$CRON_UPDATE_CMD = "cat <(fgrep -i -v \\\"$RAMP_CRON_CMD\\\" <(crontab -l)) <(echo \\\"$RAMP_CRON_JOB\\\") | crontab -";
		#echo "ECHO: $CRON_UPDATE_CMD";
		shell_exec("bash -c \"$CRON_UPDATE_CMD\"");

		# We can send an initial MQTT message to the server now
		$initial_mqtt_msg="/usr/local/bin/send_mqtt_message sm_server $server_ip[0] ramp-left $sm_zone_num $sm_ramp_days";
		shell_exec("bash -c \"$initial_mqtt_msg\"");

		# This will run an initial ramp start command 
		if ($debug) echo "  $RAMP_CRON_CMD $sm_amp_cmd\n";
		shell_exec("bash -c \"$RAMP_CRON_CMD $sm_amp_cmd\"");
	}
	else if($sm_amp_cmd == 'stop-ramp') {
		if ($debug) echo "  Stop Ramp\n";
		if(file_exists($port_ramp_file)) {
			exec("unlink $port_ramp_file");
			exec("sync");
		}

		# Remove the cron job
		$CRON_UPDATE_CMD = "crontab -l | grep -v \\\"$RAMP_CRON_CMD\\\" | crontab -";
		shell_exec("bash -c \"$CRON_UPDATE_CMD\"");

		if ($debug) echo "  $RAMP_CRON_CMD $sm_amp_cmd\n";
		shell_exec("bash -c \"$RAMP_CRON_CMD $sm_amp_cmd\"");
	}
	else if($sm_amp_cmd == 'update-config') {
		if ($debug) echo "  Update Config\n";
		$UPDATE_CFG_CMD = "/usr/local/bin/get_updated_config&";
		shell_exec("bash -c \"$UPDATE_CFG_CMD\"");
		$smPipe = fopen("/usr/local/bin/extSMChannel_uc", "w");
		if ($debug) echo "  Writing to extSMChannel_uc: $sm_amp_cmd\n";
		fwrite($smPipe, "$sm_amp_cmd");
		fclose($smPipe); 
	}
}

#
# cleanExit will be called if a signal is received requesting exit.
#
function cleanExit($signo)
{
	exit(0);
}


?>
