Hardware components | ||||||
![]() |
| × | 1 | |||
| × | 1 |
This project uses a simple IR Transmitter (in this case I used a Max Power LED kit to extend the range but any IR LED would do) connected to a spark-core, to send IR commands to the Air conditioning unit over the internet.
The project includes:
- A client (Mobile, Web-browser, etc...)
- A web server (in this case Apache - PHP)
- Spark Core
- IR LED
- AC
The web server hosts a simple User Interface that displays typical AC options. Namely: Temperature, Mode, and Fan Speed. The user can then choose whether to send the command immediately, or to schedule a command (I use this to turn on the AC for a few minutes before I wake up, and similarly for a few minutes before i go to bed :) ).
The scheduling was implemented using cron jobs on the hosting server.
The spark core acts as an IP-2-IR bridge:
The commands passed from the client to the web server are forwarded to the Spark core, which in turn forwards the commands to the Air conditioning unit.
Untitled file
Warning: Embedding code files within the project story has been deprecated. To edit this file or add more files, go to the "Software" tab. To remove this file from the story, click on it to trigger the context menu, then click the trash can button (this won't delete it from the "Software" tab).
function setAC($tempFanMode){
$authKey =getAuthKey();
$devID = getDeviceID("ir2");
$url = "https://api.spark.io/v1/devices/" . $devID . "/daikin" ;
$fields_string = "";
$fields = array(
'access_token' => urlencode($authKey),
'args' => urlencode($tempFanMode)
);
foreach($fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
rtrim($fields_string, '&');
$ch = curl_init ( );
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch,CURLOPT_POST, count($fields));
curl_setopt($ch,CURLOPT_POSTFIELDS, $fields_string);
$response1 = curl_exec ( $ch );
curl_close($ch);
}
Untitled file
Warning: Embedding code files within the project story has been deprecated. To edit this file or add more files, go to the "Software" tab. To remove this file from the story, click on it to trigger the context menu, then click the trash can button (this won't delete it from the "Software" tab).
// This #include statement was automatically added by the Spark IDE.
#include "IRremote.h"
int commadDevice(String args);
const int COMMAND_LENGTH = 27;
unsigned char daikin[COMMAND_LENGTH] = {
0x11,0xDA,0x27,0xF0,0x00,0x00,0x00,0x20,
//0 1 2 3 4 5 6 7
0x11,0xDA,0x27,0x00,0x00,0x41,0x1E,0x00,
//8 9 10 11 12 13 14 15
0xB0,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0xE3 };
//16 17 18 19 20 21 22 23 24 25 26
/*
byte 13=mode
b7 = 0
b6+b5+b4 = Mode
b3 = 0
b2 = OFF timer set
b1 = ON timer set
b0 = Air Conditioner ON
Modes: b6+b5+b4
011 = Cool
100 = Heat (temp 23)
110 = FAN (temp not shown, but 25)
000 = Fully Automatic (temp 25)
010 = DRY (temp 0xc0 = 96 degrees c)
byte 14=temp*2
byte 16=Fan
FAN control
b7+b6+b5+b4 = Fan speed
b3+b2+b1+b0 = Swing control up/down
Fan: b7+b6+b5+b4
0×30 = 1 bar - 48
0×40 = 2 bar - 64
0×50 = 3 bar - 80
0×60 = 4 bar - 96
0×70 = 5 bar - 112
0xa0 = Auto - 160
0xb0 = Not auto, moon + tree - 176
Swing control up/down:
0000 = Swing up/down off
1111 = Swing up/down on
Swing control left/right:
0000 = Swing left/right off
1111 = Swing left/right on
*/
IRsend irsend(D3); // hardwired to pin 3; use a transistor to drive the IR LED for maximal range
#define IRSTATE_EEPROM_ADDR ((byte*) 0x100)
int incomingByte;
struct IRState {
byte mode;
byte temp;
byte fan;
byte aux;
byte state;
byte enabled;
byte sched;
byte hour;
byte minutes;
long lastused;
} irstate;
void setup()
{
pinMode(D7, OUTPUT);
Spark.function("daikin", commadDevice);
}
int commadDevice(String args)
{
/*int rawSize = sizeof(rawCodes)/sizeof(int); // In this example, rawSize would evaluate to 37
irsend.sendRaw(rawCodes, rawSize, 38);
return 1;
*/
/*
Fan: b7+b6+b5+b4
0×30 = 1 bar - 48
0×40 = 2 bar - 64
0×50 = 3 bar - 80
0×60 = 4 bar - 96
0×70 = 5 bar - 112
0xa0 = 0 Auto - 160*/
/*
Modes: b6+b5+b4
0 ------000 = Fully Automatic (temp 25)
2 ------ 010 = DRY (temp 0xc0 = 96 degrees c)
3 ------011 = Cool
4 ------100 = Heat (temp 23)
5 ------110 = FAN (temp not shown, but 25)
args = temp-fan-mode
*/
if(args=="off"){
airController_off();
irstate.aux=airController_getAux();
irstate.temp=airConroller_getTemp();
irstate.fan= airConroller_getFan();
irstate.mode=airConroller_getMode();
irsend.sendDaikin(daikin, 8,0);
delay(29);
irsend.sendDaikin(daikin, 19,8);
digitalWrite(D7, LOW);
}
else{
digitalWrite(D7, HIGH);
String temps = getValue(args, '-', 0);
String fans = getValue(args, '-', 1);
String modes = getValue(args, '-', 2);
int temp = temps.toInt();
int fan = 0;
int fanc = fans.toInt();
int mode = modes.toInt();
switch (fanc) {
case 1:
fan = 48;
break;
case 2:
fan = 64;
break;
case 3:
fan = 80;
break;
case 4:
fan = 96;
break;
case 5:
fan = 112;
break;
case 0:
fan = 160;
break;
default:;
break;
}
airController_on ();
airController_setTemp (temp);
airController_setFan (fan);
airController_setMode (mode);
airController_checksum ();
irsend.sendDaikin (daikin, 8,0);
delay (29);
irsend.sendDaikin (daikin, 19,8);
}
}
String getValue(String data, char separator, int index)
{
int found = 0;
int strIndex[] = {
0, -1 };
int maxIndex = data.length()-1;
for(int i=0; i<=maxIndex && found<=index; i++){
if(data.charAt(i)==separator || i==maxIndex){
found++;
strIndex[0] = strIndex[1]+1;
strIndex[1] = (i == maxIndex) ? i+1 : i;
}
}
return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
}
uint8_t airController_checksum()
{
uint8_t sum = 0;
uint8_t i;
for(i = 0; i <= 6; i++){
sum += daikin[i];
}
daikin[7] = sum &0xFF;
sum=0;
for(i = 8; i <= 25; i++){
sum += daikin[i];
}
daikin[26] = sum &0xFF;
}
void airController_on(){
//state = ON;
daikin[13] |= 0x01;
airController_checksum();
}
void airController_off(){
//state = OFF;
daikin[13] &= 0xFE;
airController_checksum();
}
void airController_setAux(uint8_t aux){
daikin[21] = aux;
airController_checksum();
}
uint8_t airController_getAux(){
return daikin[21];
}
void airController_setTemp(uint8_t temp)
{
daikin[14] = (temp)*2;
airController_checksum();
}
void airController_setFan(uint8_t fan)
{
daikin[16] = fan;
airController_checksum();
}
uint8_t airConroller_getTemp()
{
return (daikin[14])/2;
}
uint8_t airConroller_getMode()
{
/*
Modes: b6+b5+b4
3 ------011 = Cool
4 ------100 = Heat (temp 23)
5 ------110 = FAN (temp not shown, but 25)
0 ------000 = Fully Automatic (temp 25)
2 ------ 010 = DRY (temp 0xc0 = 96 degrees c)
*/
return (daikin[13])>>4;
}
void airController_setMode(uint8_t mode)
{
daikin[13]=mode<<4 | airConroller_getState();
airController_checksum();
}
uint8_t airConroller_getState()
{
return (daikin[13])&0x01;
}
uint8_t airConroller_getFan()
{
return (daikin[16]);
}
void restartac () {
if(airConroller_getState()==1) {
airController_off();
irstate.aux=airController_getAux();
irstate.temp=airConroller_getTemp();
irstate.fan= airConroller_getFan();
irstate.mode=airConroller_getMode();
irsend.sendDaikin(daikin, 8,0);
delay(29);
irsend.sendDaikin(daikin, 19,8);
delay (10000);
airController_on();
airController_setAux(0);
airController_setTemp(irstate.temp);
airController_setFan(irstate.fan);
airController_setMode(irstate.mode);
irsend.sendDaikin(daikin, 8,0);
delay(29);
irsend.sendDaikin(daikin, 19,8);
}
}
Untitled file
Warning: Embedding code files within the project story has been deprecated. To edit this file or add more files, go to the "Software" tab. To remove this file from the story, click on it to trigger the context menu, then click the trash can button (this won't delete it from the "Software" tab).
/*
* IRremote
* Version 0.11 August, 2009
* Copyright 2009 Ken Shirriff
* For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html
*
* Modified by Paul Stoffregen <paul@pjrc.com> to support other boards and timers
* Modified by Mitra Ardron <mitra@mitra.biz>
* Added Sanyo and Mitsubishi controllers
* Modified Sony to spot the repeat codes that some Sony's send
* Modified by Gaspard van Koningsveld to trim out IRrecv, not using PWM anymore, allow setting of IR LED pin, and make it compatible with the Spark Core v1.0 (STM32F103CB based)
*
* Interrupt code based on NECIRrcv by Joe Knapp
* http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556
* Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/
*
* JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post)
*/
#include "IRremote.h"
#include "application.h"
IRsend::IRsend(int irPin) : irPin(irPin) {};
void IRsend::sendNEC(unsigned long data, int nbits)
{
enableIROut(38);
mark(NEC_HDR_MARK);
space(NEC_HDR_SPACE);
for (int i = 0; i < nbits; i++) {
if (data & TOPBIT) {
mark(NEC_BIT_MARK);
space(NEC_ONE_SPACE);
}
else {
mark(NEC_BIT_MARK);
space(NEC_ZERO_SPACE);
}
data <<= 1;
}
mark(NEC_BIT_MARK);
space(0);
}
void IRsend::sendSony(unsigned long data, int nbits) {
enableIROut(40);
mark(SONY_HDR_MARK);
space(SONY_HDR_SPACE);
data = data << (32 - nbits);
for (int i = 0; i < nbits; i++) {
if (data & TOPBIT) {
mark(SONY_ONE_MARK);
space(SONY_HDR_SPACE);
}
else {
mark(SONY_ZERO_MARK);
space(SONY_HDR_SPACE);
}
data <<= 1;
}
}
void IRsend::sendDaikin(unsigned char buf[], int len, int start) {
int data2;
enableIROut(38);
mark(DAIKIN_HDR_MARK);
space(DAIKIN_HDR_SPACE);
for (int i = start; i < start+len; i++) {
data2=buf[i];
for (int j = 0; j < 8; j++) {
if ((1 << j & data2)) {
mark(DAIKIN_ONE_MARK);
space(DAIKIN_ONE_SPACE);
}
else {
mark(DAIKIN_ZERO_MARK);
space(DAIKIN_ZERO_SPACE);
}
}
}
mark(DAIKIN_ONE_MARK);
space(DAIKIN_ZERO_SPACE);
}
void IRsend::sendRaw(unsigned int buf[], int len, int hz)
{
enableIROut(hz);
for (int i = 0; i < len; i++) {
if (i & 1) {
space(buf[i]);
}
else {
mark(buf[i]);
}
}
space(0); // Just to be sure
}
// Note: first bit must be a one (start bit)
void IRsend::sendRC5(unsigned long data, int nbits)
{
enableIROut(36);
data = data << (32 - nbits);
mark(RC5_T1); // First start bit
space(RC5_T1); // Second start bit
mark(RC5_T1); // Second start bit
for (int i = 0; i < nbits; i++) {
if (data & TOPBIT) {
space(RC5_T1); // 1 is space, then mark
mark(RC5_T1);
}
else {
mark(RC5_T1);
space(RC5_T1);
}
data <<= 1;
}
space(0); // Turn off at end
}
// Caller needs to take care of flipping the toggle bit
void IRsend::sendRC6(unsigned long data, int nbits)
{
enableIROut(36);
data = data << (32 - nbits);
mark(RC6_HDR_MARK);
space(RC6_HDR_SPACE);
mark(RC6_T1); // start bit
space(RC6_T1);
int t;
for (int i = 0; i < nbits; i++) {
if (i == 3) {
// double-wide trailer bit
t = 2 * RC6_T1;
}
else {
t = RC6_T1;
}
if (data & TOPBIT) {
mark(t);
space(t);
}
else {
space(t);
mark(t);
}
data <<= 1;
}
space(0); // Turn off at end
}
/* Sharp and DISH support by Todd Treece ( http://unionbridge.org/design/ircommand )
The Dish send function needs to be repeated 4 times, and the Sharp function
has the necessary repeat built in because of the need to invert the signal.
Sharp protocol documentation:
http://www.sbprojects.com/knowledge/ir/sharp.htm
Here are the LIRC files that I found that seem to match the remote codes
from the oscilloscope:
Sharp LCD TV:
http://lirc.sourceforge.net/remotes/sharp/GA538WJSA
DISH NETWORK (echostar 301):
http://lirc.sourceforge.net/remotes/echostar/301_501_3100_5100_58xx_59xx
For the DISH codes, only send the last for characters of the hex.
i.e. use 0x1C10 instead of 0x0000000000001C10 which is listed in the
linked LIRC file.
*/
void IRsend::sendSharp(unsigned long data, int nbits) {
unsigned long invertdata = data ^ SHARP_TOGGLE_MASK;
enableIROut(38);
for (int i = 0; i < nbits; i++) {
if (data & 0x4000) {
mark(SHARP_BIT_MARK);
space(SHARP_ONE_SPACE);
}
else {
mark(SHARP_BIT_MARK);
space(SHARP_ZERO_SPACE);
}
data <<= 1;
}
mark(SHARP_BIT_MARK);
space(SHARP_ZERO_SPACE);
delay(46);
for (int i = 0; i < nbits; i++) {
if (invertdata & 0x4000) {
mark(SHARP_BIT_MARK);
space(SHARP_ONE_SPACE);
}
else {
mark(SHARP_BIT_MARK);
space(SHARP_ZERO_SPACE);
}
invertdata <<= 1;
}
mark(SHARP_BIT_MARK);
space(SHARP_ZERO_SPACE);
delay(46);
}
void IRsend::sendDISH(unsigned long data, int nbits)
{
enableIROut(56);
mark(DISH_HDR_MARK);
space(DISH_HDR_SPACE);
for (int i = 0; i < nbits; i++) {
if (data & DISH_TOP_BIT) {
mark(DISH_BIT_MARK);
space(DISH_ONE_SPACE);
}
else {
mark(DISH_BIT_MARK);
space(DISH_ZERO_SPACE);
}
data <<= 1;
}
}
void IRsend::sendPanasonic(unsigned int address, unsigned long data) {
enableIROut(35);
mark(PANASONIC_HDR_MARK);
space(PANASONIC_HDR_SPACE);
for(int i=0;i<16;i++)
{
mark(PANASONIC_BIT_MARK);
if (address & 0x8000) {
space(PANASONIC_ONE_SPACE);
} else {
space(PANASONIC_ZERO_SPACE);
}
address <<= 1;
}
for (int i=0; i < 32; i++) {
mark(PANASONIC_BIT_MARK);
if (data & TOPBIT) {
space(PANASONIC_ONE_SPACE);
} else {
space(PANASONIC_ZERO_SPACE);
}
data <<= 1;
}
mark(PANASONIC_BIT_MARK);
space(0);
}
void IRsend::sendJVC(unsigned long data, int nbits, int repeat)
{
enableIROut(38);
data = data << (32 - nbits);
if (!repeat){
mark(JVC_HDR_MARK);
space(JVC_HDR_SPACE);
}
for (int i = 0; i < nbits; i++) {
if (data & TOPBIT) {
mark(JVC_BIT_MARK);
space(JVC_ONE_SPACE);
}
else {
mark(JVC_BIT_MARK);
space(JVC_ZERO_SPACE);
}
data <<= 1;
}
mark(JVC_BIT_MARK);
space(0);
}
void IRsend::mark(int time) {
// Sends an IR mark (frequency burst output) for the specified number of microseconds.
noInterrupts();
while (time > 0) {
digitalWrite(irPin, HIGH); // this takes about 3 microseconds to happen
delayMicroseconds(burstWait);
digitalWrite(irPin, LOW); // this also takes about 3 microseconds
delayMicroseconds(burstWait);
time -= burstLength;
}
interrupts();
}
void IRsend::space(int time) {
// Sends an IR space (no output) for the specified number of microseconds.
digitalWrite(irPin, LOW); // Takes about 3 microsecondes
if (time > 3) {
delayMicroseconds(time - 3);
}
}
void IRsend::enableIROut(int khz) {
// Enables IR output. The khz value controls the modulation frequency in kilohertz.
// MAX frequency is 166khz.
pinMode(irPin, OUTPUT);
digitalWrite(irPin, LOW);
// This is the time to wait with the IR LED on and off to make the frequency, in microseconds.
// The - 3.0 at the end is because digitalWrite() takes about 3 microseconds. Info from:
// https://github.com/eflynch/sparkcoreiremitter/blob/master/ir_emitter/ir_emitter.ino
burstWait = round(1.0 / khz * 1000.0 / 2.0 - 3.0);
// This is the total time of a period, in microseconds.
burstLength = round(1.0 / khz * 1000.0);
}
Untitled file
Warning: Embedding code files within the project story has been deprecated. To edit this file or add more files, go to the "Software" tab. To remove this file from the story, click on it to trigger the context menu, then click the trash can button (this won't delete it from the "Software" tab).
/*
* IRremote
* Version 0.1 July, 2009
* Copyright 2009 Ken Shirriff
* For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.htm http://arcfn.com
* Edited by Mitra to add new controller SANYO
*
* Interrupt code based on NECIRrcv by Joe Knapp
* http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556
* Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/
*
* JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post)
*/
#ifndef IRremote_h
#define IRremote_h
class IRsend
{
const int irPin;
int burstWait;
int burstLength;
public:
IRsend(int irPin);
void sendNEC(unsigned long data, int nbits);
void sendSony(unsigned long data, int nbits);
// Neither Sanyo nor Mitsubishi send is implemented yet
// void sendSanyo(unsigned long data, int nbits);
// void sendMitsubishi(unsigned long data, int nbits);
void sendDaikin(unsigned char buf[], int len,int start);
void sendRaw(unsigned int buf[], int len, int hz);
void sendRC5(unsigned long data, int nbits);
void sendRC6(unsigned long data, int nbits);
void sendSharp(unsigned long data, int nbits);
void sendDISH(unsigned long data, int nbits);
void sendPanasonic(unsigned int address, unsigned long data);
void sendJVC(unsigned long data, int nbits, int repeat); // *Note instead of sending the REPEAT constant if you want the JVC repeat signal sent, send the original code value and change the repeat argument from 0 to 1. JVC protocol repeats by skipping the header NOT by sending a separate code value like NEC does.
private:
void enableIROut(int khz);
void mark(int usec);
void space(int usec);
}
;
#define DAIKIN_HDR_MARK 3650 //DAIKIN_ZERO_MARK*8
#define DAIKIN_HDR_SPACE 1623 //DAIKIN_ZERO_MARK*4
#define DAIKIN_ONE_SPACE 1280
#define DAIKIN_ONE_MARK 428
#define DAIKIN_ZERO_MARK 428
#define DAIKIN_ZERO_SPACE 428
// Constants for sending IR codes
#define NEC_HDR_MARK 9000
#define NEC_HDR_SPACE 4500
#define NEC_BIT_MARK 560
#define NEC_ONE_SPACE 1600
#define NEC_ZERO_SPACE 560
#define NEC_RPT_SPACE 2250
#define SONY_HDR_MARK 2400
#define SONY_HDR_SPACE 600
#define SONY_ONE_MARK 1200
#define SONY_ZERO_MARK 600
#define SONY_RPT_LENGTH 45000
#define SONY_DOUBLE_SPACE_USECS 500 // usually ssee 713 - not using ticks as get number wrapround
// SA 8650B
#define SANYO_HDR_MARK 3500 // seen range 3500
#define SANYO_HDR_SPACE 950 // seen 950
#define SANYO_ONE_MARK 2400 // seen 2400
#define SANYO_ZERO_MARK 700 // seen 700
#define SANYO_DOUBLE_SPACE_USECS 800 // usually ssee 713 - not using ticks as get number wrapround
#define SANYO_RPT_LENGTH 45000
// Mitsubishi RM 75501
// 14200 7 41 7 42 7 42 7 17 7 17 7 18 7 41 7 18 7 17 7 17 7 18 7 41 8 17 7 17 7 18 7 17 7
// #define MITSUBISHI_HDR_MARK 250 // seen range 3500
#define MITSUBISHI_HDR_SPACE 350 // 7*50+100
#define MITSUBISHI_ONE_MARK 1950 // 41*50-100
#define MITSUBISHI_ZERO_MARK 750 // 17*50-100
// #define MITSUBISHI_DOUBLE_SPACE_USECS 800 // usually ssee 713 - not using ticks as get number wrapround
// #define MITSUBISHI_RPT_LENGTH 45000
#define RC5_T1 889
#define RC5_RPT_LENGTH 46000
#define RC6_HDR_MARK 2666
#define RC6_HDR_SPACE 889
#define RC6_T1 444
#define RC6_RPT_LENGTH 46000
#define SHARP_BIT_MARK 245
#define SHARP_ONE_SPACE 1805
#define SHARP_ZERO_SPACE 795
#define SHARP_GAP 600000
#define SHARP_TOGGLE_MASK 0x3FF
#define SHARP_RPT_SPACE 3000
#define DISH_HDR_MARK 400
#define DISH_HDR_SPACE 6100
#define DISH_BIT_MARK 400
#define DISH_ONE_SPACE 1700
#define DISH_ZERO_SPACE 2800
#define DISH_RPT_SPACE 6200
#define DISH_TOP_BIT 0x8000
#define PANASONIC_HDR_MARK 3502
#define PANASONIC_HDR_SPACE 1750
#define PANASONIC_BIT_MARK 502
#define PANASONIC_ONE_SPACE 1244
#define PANASONIC_ZERO_SPACE 400
#define JVC_HDR_MARK 8000
#define JVC_HDR_SPACE 4000
#define JVC_BIT_MARK 600
#define JVC_ONE_SPACE 1600
#define JVC_ZERO_SPACE 550
#define JVC_RPT_LENGTH 60000
#define SHARP_BITS 15
#define DAIKIN_BITS 99
#define DISH_BITS 16
#define TOPBIT 0x80000000
#endif
Untitled file
Warning: Embedding code files within the project story has been deprecated. To edit this file or add more files, go to the "Software" tab. To remove this file from the story, click on it to trigger the context menu, then click the trash can button (this won't delete it from the "Software" tab).
<?php require_once('CronClass.php');
if (isset($_POST["cronSchedString"]) && isset($_POST["tempFanMode"])) {
$allcronjobs = getAllCronJobs();
$newcron = new CronClass('ac', $_POST["cronSchedString"], ["tempFanMode" => $_POST["tempFanMode"],]);
array_push($allcronjobs, $newcron);
writeToCronTab($allcronjobs);
echo showCronJobs($allcronjobs);
}
if (isset($_POST["getCrons"]) ) {
$allcronjobs = getAllCronJobs();
echo showCronJobs($allcronjobs);
}
if (isset($_POST["removeId"]) ) {
$allcronjobs = getAllCronJobs();
array_splice($allcronjobs,$_POST["removeId"],1);
writeToCronTab($allcronjobs);
$allcronjobs = getAllCronJobs();
echo showCronJobs($allcronjobs);
}
if (isset($_POST["modId"]) && isset($_POST["modcronSchedString"]) && isset($_POST["modtempFanMode"])) {
$allcronjobs = getAllCronJobs();
$modcron = new CronClass('ac', $_POST["modcronSchedString"], ["tempFanMode" => $_POST["modtempFanMode"],]);
unset($allcronjobs[$_POST["modId"]]);
$allcronjobs[$_POST["modId"]] = $modcron;
writeToCronTab($allcronjobs);
$allcronjobs = getAllCronJobs();
echo showCronJobs($allcronjobs);
}
function writeToCronTab($cronjobs){
$cronstring = '';
foreach ($cronjobs as $cron) {
if($cronstring != ''){
$cronstring = $cronstring .PHP_EOL;
}
$cronstring = $cronstring .$cron->getCronString() ;
}
$cronstring = $cronstring .PHP_EOL;
file_put_contents('/tmp/crontab.txt', $cronstring);
echo exec('crontab /tmp/crontab.txt');
}
function showCronJobs($cronjobs){
$json = array();
foreach ($cronjobs as $cronjob) {
$bus = array(
'script' => $cronjob->getPhpScript(),
'cron' => $cronjob->getCronSched(),
'tempfanmode' => $cronjob->getKeyValue("tempFanMode")
);
array_push($json, $bus);
}
$jsonstring = json_encode($json);
return $jsonstring;
}
function getAllCronJobs(){
$cronjobarr = array();
$output = shell_exec('crontab -l');
$cronjobs = explode("\n", $output);
foreach ($cronjobs as $cronjob) {
if(strlen($cronjob)>0){
$obj = getCronFromString($cronjob);
array_push($cronjobarr, $obj);
}
}
return $cronjobarr;
}
function getCronFromString($cronstring) {
$phpscript = get_string_between($cronstring, "/php/", ".php");
$cronschedule = substr($cronstring,0,strpos($cronstring, " /usr/", 1));
$vars = substr(strrchr($cronstring, "?"), 1);
$params = explode("&", $vars);
$kva = array();
foreach ($params as $param) {
$keyval = explode("=", $param);
$key = $keyval[0];
$val = $keyval[1];
$kva[$key] = $val;
}
return $rescron = new CronClass($phpscript, $cronschedule, $kva);
}
function get_string_between($string, $start, $end){
$string = " ".$string;
$ini = strpos($string,$start);
if ($ini == 0) return "";
$ini += strlen($start);
$len = strpos($string,$end,$ini) - $ini;
return substr($string,$ini,$len);
}
?>
I will be uploading more information on the project soon :)
function setAC($tempFanMode){
$authKey =getAuthKey();
$devID = getDeviceID("ir2");
$url = "https://api.spark.io/v1/devices/" . $devID . "/daikin" ;
$fields_string = "";
$fields = array(
'access_token' => urlencode($authKey),
'args' => urlencode($tempFanMode)
);
foreach($fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
rtrim($fields_string, '&');
$ch = curl_init ( );
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch,CURLOPT_POST, count($fields));
curl_setopt($ch,CURLOPT_POSTFIELDS, $fields_string);
$response1 = curl_exec ( $ch );
curl_close($ch);
}
// This #include statement was automatically added by the Spark IDE.
#include "IRremote.h"
int commadDevice(String args);
const int COMMAND_LENGTH = 27;
unsigned char daikin[COMMAND_LENGTH] = {
0x11,0xDA,0x27,0xF0,0x00,0x00,0x00,0x20,
//0 1 2 3 4 5 6 7
0x11,0xDA,0x27,0x00,0x00,0x41,0x1E,0x00,
//8 9 10 11 12 13 14 15
0xB0,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0xE3 };
//16 17 18 19 20 21 22 23 24 25 26
/*
byte 13=mode
b7 = 0
b6+b5+b4 = Mode
b3 = 0
b2 = OFF timer set
b1 = ON timer set
b0 = Air Conditioner ON
Modes: b6+b5+b4
011 = Cool
100 = Heat (temp 23)
110 = FAN (temp not shown, but 25)
000 = Fully Automatic (temp 25)
010 = DRY (temp 0xc0 = 96 degrees c)
byte 14=temp*2
byte 16=Fan
FAN control
b7+b6+b5+b4 = Fan speed
b3+b2+b1+b0 = Swing control up/down
Fan: b7+b6+b5+b4
030 = 1 bar - 48
040 = 2 bar - 64
050 = 3 bar - 80
060 = 4 bar - 96
070 = 5 bar - 112
0xa0 = Auto - 160
0xb0 = Not auto, moon + tree - 176
Swing control up/down:
0000 = Swing up/down off
1111 = Swing up/down on
Swing control left/right:
0000 = Swing left/right off
1111 = Swing left/right on
*/
IRsend irsend(D3); // hardwired to pin 3; use a transistor to drive the IR LED for maximal range
#define IRSTATE_EEPROM_ADDR ((byte*) 0x100)
int incomingByte;
struct IRState {
byte mode;
byte temp;
byte fan;
byte aux;
byte state;
byte enabled;
byte sched;
byte hour;
byte minutes;
long lastused;
} irstate;
void setup()
{
pinMode(D7, OUTPUT);
Spark.function("daikin", commadDevice);
}
int commadDevice(String args)
{
/*int rawSize = sizeof(rawCodes)/sizeof(int); // In this example, rawSize would evaluate to 37
irsend.sendRaw(rawCodes, rawSize, 38);
return 1;
*/
/*
Fan: b7+b6+b5+b4
030 = 1 bar - 48
040 = 2 bar - 64
050 = 3 bar - 80
060 = 4 bar - 96
070 = 5 bar - 112
0xa0 = 0 Auto - 160*/
/*
Modes: b6+b5+b4
0 ------000 = Fully Automatic (temp 25)
2 ------ 010 = DRY (temp 0xc0 = 96 degrees c)
3 ------011 = Cool
4 ------100 = Heat (temp 23)
5 ------110 = FAN (temp not shown, but 25)
args = temp-fan-mode
*/
if(args=="off"){
airController_off();
irstate.aux=airController_getAux();
irstate.temp=airConroller_getTemp();
irstate.fan= airConroller_getFan();
irstate.mode=airConroller_getMode();
irsend.sendDaikin(daikin, 8,0);
delay(29);
irsend.sendDaikin(daikin, 19,8);
digitalWrite(D7, LOW);
}
else{
digitalWrite(D7, HIGH);
String temps = getValue(args, '-', 0);
String fans = getValue(args, '-', 1);
String modes = getValue(args, '-', 2);
int temp = temps.toInt();
int fan = 0;
int fanc = fans.toInt();
int mode = modes.toInt();
switch (fanc) {
case 1:
fan = 48;
break;
case 2:
fan = 64;
break;
case 3:
fan = 80;
break;
case 4:
fan = 96;
break;
case 5:
fan = 112;
break;
case 0:
fan = 160;
break;
default:;
break;
}
airController_on ();
airController_setTemp (temp);
airController_setFan (fan);
airController_setMode (mode);
airController_checksum ();
irsend.sendDaikin (daikin, 8,0);
delay (29);
irsend.sendDaikin (daikin, 19,8);
}
}
String getValue(String data, char separator, int index)
{
int found = 0;
int strIndex[] = {
0, -1 };
int maxIndex = data.length()-1;
for(int i=0; i<=maxIndex && found<=index; i++){
if(data.charAt(i)==separator || i==maxIndex){
found++;
strIndex[0] = strIndex[1]+1;
strIndex[1] = (i == maxIndex) ? i+1 : i;
}
}
return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
}
uint8_t airController_checksum()
{
uint8_t sum = 0;
uint8_t i;
for(i = 0; i <= 6; i++){
sum += daikin[i];
}
daikin[7] = sum &0xFF;
sum=0;
for(i = 8; i <= 25; i++){
sum += daikin[i];
}
daikin[26] = sum &0xFF;
}
void airController_on(){
//state = ON;
daikin[13] |= 0x01;
airController_checksum();
}
void airController_off(){
//state = OFF;
daikin[13] &= 0xFE;
airController_checksum();
}
void airController_setAux(uint8_t aux){
daikin[21] = aux;
airController_checksum();
}
uint8_t airController_getAux(){
return daikin[21];
}
void airController_setTemp(uint8_t temp)
{
daikin[14] = (temp)*2;
airController_checksum();
}
void airController_setFan(uint8_t fan)
{
daikin[16] = fan;
airController_checksum();
}
uint8_t airConroller_getTemp()
{
return (daikin[14])/2;
}
uint8_t airConroller_getMode()
{
/*
Modes: b6+b5+b4
3 ------011 = Cool
4 ------100 = Heat (temp 23)
5 ------110 = FAN (temp not shown, but 25)
0 ------000 = Fully Automatic (temp 25)
2 ------ 010 = DRY (temp 0xc0 = 96 degrees c)
*/
return (daikin[13])>>4;
}
void airController_setMode(uint8_t mode)
{
daikin[13]=mode<<4 | airConroller_getState();
airController_checksum();
}
uint8_t airConroller_getState()
{
return (daikin[13])&0x01;
}
uint8_t airConroller_getFan()
{
return (daikin[16]);
}
void restartac () {
if(airConroller_getState()==1) {
airController_off();
irstate.aux=airController_getAux();
irstate.temp=airConroller_getTemp();
irstate.fan= airConroller_getFan();
irstate.mode=airConroller_getMode();
irsend.sendDaikin(daikin, 8,0);
delay(29);
irsend.sendDaikin(daikin, 19,8);
delay (10000);
airController_on();
airController_setAux(0);
airController_setTemp(irstate.temp);
airController_setFan(irstate.fan);
airController_setMode(irstate.mode);
irsend.sendDaikin(daikin, 8,0);
delay(29);
irsend.sendDaikin(daikin, 19,8);
}
}
file_10391.txt
C/C++/*
* IRremote
* Version 0.11 August, 2009
* Copyright 2009 Ken Shirriff
* For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html
*
* Modified by Paul Stoffregen <paul@pjrc.com> to support other boards and timers
* Modified by Mitra Ardron <mitra@mitra.biz>
* Added Sanyo and Mitsubishi controllers
* Modified Sony to spot the repeat codes that some Sony's send
* Modified by Gaspard van Koningsveld to trim out IRrecv, not using PWM anymore, allow setting of IR LED pin, and make it compatible with the Spark Core v1.0 (STM32F103CB based)
*
* Interrupt code based on NECIRrcv by Joe Knapp
* http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556
* Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/
*
* JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post)
*/
#include "IRremote.h"
#include "application.h"
IRsend::IRsend(int irPin) : irPin(irPin) {};
void IRsend::sendNEC(unsigned long data, int nbits)
{
enableIROut(38);
mark(NEC_HDR_MARK);
space(NEC_HDR_SPACE);
for (int i = 0; i < nbits; i++) {
if (data & TOPBIT) {
mark(NEC_BIT_MARK);
space(NEC_ONE_SPACE);
}
else {
mark(NEC_BIT_MARK);
space(NEC_ZERO_SPACE);
}
data <<= 1;
}
mark(NEC_BIT_MARK);
space(0);
}
void IRsend::sendSony(unsigned long data, int nbits) {
enableIROut(40);
mark(SONY_HDR_MARK);
space(SONY_HDR_SPACE);
data = data << (32 - nbits);
for (int i = 0; i < nbits; i++) {
if (data & TOPBIT) {
mark(SONY_ONE_MARK);
space(SONY_HDR_SPACE);
}
else {
mark(SONY_ZERO_MARK);
space(SONY_HDR_SPACE);
}
data <<= 1;
}
}
void IRsend::sendDaikin(unsigned char buf[], int len, int start) {
int data2;
enableIROut(38);
mark(DAIKIN_HDR_MARK);
space(DAIKIN_HDR_SPACE);
for (int i = start; i < start+len; i++) {
data2=buf[i];
for (int j = 0; j < 8; j++) {
if ((1 << j & data2)) {
mark(DAIKIN_ONE_MARK);
space(DAIKIN_ONE_SPACE);
}
else {
mark(DAIKIN_ZERO_MARK);
space(DAIKIN_ZERO_SPACE);
}
}
}
mark(DAIKIN_ONE_MARK);
space(DAIKIN_ZERO_SPACE);
}
void IRsend::sendRaw(unsigned int buf[], int len, int hz)
{
enableIROut(hz);
for (int i = 0; i < len; i++) {
if (i & 1) {
space(buf[i]);
}
else {
mark(buf[i]);
}
}
space(0); // Just to be sure
}
// Note: first bit must be a one (start bit)
void IRsend::sendRC5(unsigned long data, int nbits)
{
enableIROut(36);
data = data << (32 - nbits);
mark(RC5_T1); // First start bit
space(RC5_T1); // Second start bit
mark(RC5_T1); // Second start bit
for (int i = 0; i < nbits; i++) {
if (data & TOPBIT) {
space(RC5_T1); // 1 is space, then mark
mark(RC5_T1);
}
else {
mark(RC5_T1);
space(RC5_T1);
}
data <<= 1;
}
space(0); // Turn off at end
}
// Caller needs to take care of flipping the toggle bit
void IRsend::sendRC6(unsigned long data, int nbits)
{
enableIROut(36);
data = data << (32 - nbits);
mark(RC6_HDR_MARK);
space(RC6_HDR_SPACE);
mark(RC6_T1); // start bit
space(RC6_T1);
int t;
for (int i = 0; i < nbits; i++) {
if (i == 3) {
// double-wide trailer bit
t = 2 * RC6_T1;
}
else {
t = RC6_T1;
}
if (data & TOPBIT) {
mark(t);
space(t);
}
else {
space(t);
mark(t);
}
data <<= 1;
}
space(0); // Turn off at end
}
/* Sharp and DISH support by Todd Treece ( http://unionbridge.org/design/ircommand )
The Dish send function needs to be repeated 4 times, and the Sharp function
has the necessary repeat built in because of the need to invert the signal.
Sharp protocol documentation:
http://www.sbprojects.com/knowledge/ir/sharp.htm
Here are the LIRC files that I found that seem to match the remote codes
from the oscilloscope:
Sharp LCD TV:
http://lirc.sourceforge.net/remotes/sharp/GA538WJSA
DISH NETWORK (echostar 301):
http://lirc.sourceforge.net/remotes/echostar/301_501_3100_5100_58xx_59xx
For the DISH codes, only send the last for characters of the hex.
i.e. use 0x1C10 instead of 0x0000000000001C10 which is listed in the
linked LIRC file.
*/
void IRsend::sendSharp(unsigned long data, int nbits) {
unsigned long invertdata = data ^ SHARP_TOGGLE_MASK;
enableIROut(38);
for (int i = 0; i < nbits; i++) {
if (data & 0x4000) {
mark(SHARP_BIT_MARK);
space(SHARP_ONE_SPACE);
}
else {
mark(SHARP_BIT_MARK);
space(SHARP_ZERO_SPACE);
}
data <<= 1;
}
mark(SHARP_BIT_MARK);
space(SHARP_ZERO_SPACE);
delay(46);
for (int i = 0; i < nbits; i++) {
if (invertdata & 0x4000) {
mark(SHARP_BIT_MARK);
space(SHARP_ONE_SPACE);
}
else {
mark(SHARP_BIT_MARK);
space(SHARP_ZERO_SPACE);
}
invertdata <<= 1;
}
mark(SHARP_BIT_MARK);
space(SHARP_ZERO_SPACE);
delay(46);
}
void IRsend::sendDISH(unsigned long data, int nbits)
{
enableIROut(56);
mark(DISH_HDR_MARK);
space(DISH_HDR_SPACE);
for (int i = 0; i < nbits; i++) {
if (data & DISH_TOP_BIT) {
mark(DISH_BIT_MARK);
space(DISH_ONE_SPACE);
}
else {
mark(DISH_BIT_MARK);
space(DISH_ZERO_SPACE);
}
data <<= 1;
}
}
void IRsend::sendPanasonic(unsigned int address, unsigned long data) {
enableIROut(35);
mark(PANASONIC_HDR_MARK);
space(PANASONIC_HDR_SPACE);
for(int i=0;i<16;i++)
{
mark(PANASONIC_BIT_MARK);
if (address & 0x8000) {
space(PANASONIC_ONE_SPACE);
} else {
space(PANASONIC_ZERO_SPACE);
}
address <<= 1;
}
for (int i=0; i < 32; i++) {
mark(PANASONIC_BIT_MARK);
if (data & TOPBIT) {
space(PANASONIC_ONE_SPACE);
} else {
space(PANASONIC_ZERO_SPACE);
}
data <<= 1;
}
mark(PANASONIC_BIT_MARK);
space(0);
}
void IRsend::sendJVC(unsigned long data, int nbits, int repeat)
{
enableIROut(38);
data = data << (32 - nbits);
if (!repeat){
mark(JVC_HDR_MARK);
space(JVC_HDR_SPACE);
}
for (int i = 0; i < nbits; i++) {
if (data & TOPBIT) {
mark(JVC_BIT_MARK);
space(JVC_ONE_SPACE);
}
else {
mark(JVC_BIT_MARK);
space(JVC_ZERO_SPACE);
}
data <<= 1;
}
mark(JVC_BIT_MARK);
space(0);
}
void IRsend::mark(int time) {
// Sends an IR mark (frequency burst output) for the specified number of microseconds.
noInterrupts();
while (time > 0) {
digitalWrite(irPin, HIGH); // this takes about 3 microseconds to happen
delayMicroseconds(burstWait);
digitalWrite(irPin, LOW); // this also takes about 3 microseconds
delayMicroseconds(burstWait);
time -= burstLength;
}
interrupts();
}
void IRsend::space(int time) {
// Sends an IR space (no output) for the specified number of microseconds.
digitalWrite(irPin, LOW); // Takes about 3 microsecondes
if (time > 3) {
delayMicroseconds(time - 3);
}
}
void IRsend::enableIROut(int khz) {
// Enables IR output. The khz value controls the modulation frequency in kilohertz.
// MAX frequency is 166khz.
pinMode(irPin, OUTPUT);
digitalWrite(irPin, LOW);
// This is the time to wait with the IR LED on and off to make the frequency, in microseconds.
// The - 3.0 at the end is because digitalWrite() takes about 3 microseconds. Info from:
// https://github.com/eflynch/sparkcoreiremitter/blob/master/ir_emitter/ir_emitter.ino
burstWait = round(1.0 / khz * 1000.0 / 2.0 - 3.0);
// This is the total time of a period, in microseconds.
burstLength = round(1.0 / khz * 1000.0);
}
/*
* IRremote
* Version 0.1 July, 2009
* Copyright 2009 Ken Shirriff
* For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.htm http://arcfn.com
* Edited by Mitra to add new controller SANYO
*
* Interrupt code based on NECIRrcv by Joe Knapp
* http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556
* Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/
*
* JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post)
*/
#ifndef IRremote_h
#define IRremote_h
class IRsend
{
const int irPin;
int burstWait;
int burstLength;
public:
IRsend(int irPin);
void sendNEC(unsigned long data, int nbits);
void sendSony(unsigned long data, int nbits);
// Neither Sanyo nor Mitsubishi send is implemented yet
// void sendSanyo(unsigned long data, int nbits);
// void sendMitsubishi(unsigned long data, int nbits);
void sendDaikin(unsigned char buf[], int len,int start);
void sendRaw(unsigned int buf[], int len, int hz);
void sendRC5(unsigned long data, int nbits);
void sendRC6(unsigned long data, int nbits);
void sendSharp(unsigned long data, int nbits);
void sendDISH(unsigned long data, int nbits);
void sendPanasonic(unsigned int address, unsigned long data);
void sendJVC(unsigned long data, int nbits, int repeat); // *Note instead of sending the REPEAT constant if you want the JVC repeat signal sent, send the original code value and change the repeat argument from 0 to 1. JVC protocol repeats by skipping the header NOT by sending a separate code value like NEC does.
private:
void enableIROut(int khz);
void mark(int usec);
void space(int usec);
}
;
#define DAIKIN_HDR_MARK 3650 //DAIKIN_ZERO_MARK*8
#define DAIKIN_HDR_SPACE 1623 //DAIKIN_ZERO_MARK*4
#define DAIKIN_ONE_SPACE 1280
#define DAIKIN_ONE_MARK 428
#define DAIKIN_ZERO_MARK 428
#define DAIKIN_ZERO_SPACE 428
// Constants for sending IR codes
#define NEC_HDR_MARK 9000
#define NEC_HDR_SPACE 4500
#define NEC_BIT_MARK 560
#define NEC_ONE_SPACE 1600
#define NEC_ZERO_SPACE 560
#define NEC_RPT_SPACE 2250
#define SONY_HDR_MARK 2400
#define SONY_HDR_SPACE 600
#define SONY_ONE_MARK 1200
#define SONY_ZERO_MARK 600
#define SONY_RPT_LENGTH 45000
#define SONY_DOUBLE_SPACE_USECS 500 // usually ssee 713 - not using ticks as get number wrapround
// SA 8650B
#define SANYO_HDR_MARK 3500 // seen range 3500
#define SANYO_HDR_SPACE 950 // seen 950
#define SANYO_ONE_MARK 2400 // seen 2400
#define SANYO_ZERO_MARK 700 // seen 700
#define SANYO_DOUBLE_SPACE_USECS 800 // usually ssee 713 - not using ticks as get number wrapround
#define SANYO_RPT_LENGTH 45000
// Mitsubishi RM 75501
// 14200 7 41 7 42 7 42 7 17 7 17 7 18 7 41 7 18 7 17 7 17 7 18 7 41 8 17 7 17 7 18 7 17 7
// #define MITSUBISHI_HDR_MARK 250 // seen range 3500
#define MITSUBISHI_HDR_SPACE 350 // 7*50+100
#define MITSUBISHI_ONE_MARK 1950 // 41*50-100
#define MITSUBISHI_ZERO_MARK 750 // 17*50-100
// #define MITSUBISHI_DOUBLE_SPACE_USECS 800 // usually ssee 713 - not using ticks as get number wrapround
// #define MITSUBISHI_RPT_LENGTH 45000
#define RC5_T1 889
#define RC5_RPT_LENGTH 46000
#define RC6_HDR_MARK 2666
#define RC6_HDR_SPACE 889
#define RC6_T1 444
#define RC6_RPT_LENGTH 46000
#define SHARP_BIT_MARK 245
#define SHARP_ONE_SPACE 1805
#define SHARP_ZERO_SPACE 795
#define SHARP_GAP 600000
#define SHARP_TOGGLE_MASK 0x3FF
#define SHARP_RPT_SPACE 3000
#define DISH_HDR_MARK 400
#define DISH_HDR_SPACE 6100
#define DISH_BIT_MARK 400
#define DISH_ONE_SPACE 1700
#define DISH_ZERO_SPACE 2800
#define DISH_RPT_SPACE 6200
#define DISH_TOP_BIT 0x8000
#define PANASONIC_HDR_MARK 3502
#define PANASONIC_HDR_SPACE 1750
#define PANASONIC_BIT_MARK 502
#define PANASONIC_ONE_SPACE 1244
#define PANASONIC_ZERO_SPACE 400
#define JVC_HDR_MARK 8000
#define JVC_HDR_SPACE 4000
#define JVC_BIT_MARK 600
#define JVC_ONE_SPACE 1600
#define JVC_ZERO_SPACE 550
#define JVC_RPT_LENGTH 60000
#define SHARP_BITS 15
#define DAIKIN_BITS 99
#define DISH_BITS 16
#define TOPBIT 0x80000000
#endif
<?php require_once('CronClass.php');
if (isset($_POST["cronSchedString"]) && isset($_POST["tempFanMode"])) {
$allcronjobs = getAllCronJobs();
$newcron = new CronClass('ac', $_POST["cronSchedString"], ["tempFanMode" => $_POST["tempFanMode"],]);
array_push($allcronjobs, $newcron);
writeToCronTab($allcronjobs);
echo showCronJobs($allcronjobs);
}
if (isset($_POST["getCrons"]) ) {
$allcronjobs = getAllCronJobs();
echo showCronJobs($allcronjobs);
}
if (isset($_POST["removeId"]) ) {
$allcronjobs = getAllCronJobs();
array_splice($allcronjobs,$_POST["removeId"],1);
writeToCronTab($allcronjobs);
$allcronjobs = getAllCronJobs();
echo showCronJobs($allcronjobs);
}
if (isset($_POST["modId"]) && isset($_POST["modcronSchedString"]) && isset($_POST["modtempFanMode"])) {
$allcronjobs = getAllCronJobs();
$modcron = new CronClass('ac', $_POST["modcronSchedString"], ["tempFanMode" => $_POST["modtempFanMode"],]);
unset($allcronjobs[$_POST["modId"]]);
$allcronjobs[$_POST["modId"]] = $modcron;
writeToCronTab($allcronjobs);
$allcronjobs = getAllCronJobs();
echo showCronJobs($allcronjobs);
}
function writeToCronTab($cronjobs){
$cronstring = '';
foreach ($cronjobs as $cron) {
if($cronstring != ''){
$cronstring = $cronstring .PHP_EOL;
}
$cronstring = $cronstring .$cron->getCronString() ;
}
$cronstring = $cronstring .PHP_EOL;
file_put_contents('/tmp/crontab.txt', $cronstring);
echo exec('crontab /tmp/crontab.txt');
}
function showCronJobs($cronjobs){
$json = array();
foreach ($cronjobs as $cronjob) {
$bus = array(
'script' => $cronjob->getPhpScript(),
'cron' => $cronjob->getCronSched(),
'tempfanmode' => $cronjob->getKeyValue("tempFanMode")
);
array_push($json, $bus);
}
$jsonstring = json_encode($json);
return $jsonstring;
}
function getAllCronJobs(){
$cronjobarr = array();
$output = shell_exec('crontab -l');
$cronjobs = explode("\n", $output);
foreach ($cronjobs as $cronjob) {
if(strlen($cronjob)>0){
$obj = getCronFromString($cronjob);
array_push($cronjobarr, $obj);
}
}
return $cronjobarr;
}
function getCronFromString($cronstring) {
$phpscript = get_string_between($cronstring, "/php/", ".php");
$cronschedule = substr($cronstring,0,strpos($cronstring, " /usr/", 1));
$vars = substr(strrchr($cronstring, "?"), 1);
$params = explode("&", $vars);
$kva = array();
foreach ($params as $param) {
$keyval = explode("=", $param);
$key = $keyval[0];
$val = $keyval[1];
$kva[$key] = $val;
}
return $rescron = new CronClass($phpscript, $cronschedule, $kva);
}
function get_string_between($string, $start, $end){
$string = " ".$string;
$ini = strpos($string,$start);
if ($ini == 0) return "";
$ini += strlen($start);
$len = strpos($string,$end,$ini) - $ini;
return substr($string,$ini,$len);
}
?>
Comments
Please log in or sign up to comment.