Page 1 of 8

[Python] Control Mitsubishi MAC-557IF-E airconditioning

Posted: Monday 03 August 2015 23:17
by gysmo38
Hello,

After a while, i finnaly manage to control my mitsubishi units with perl script.

I share with you the code:

Code: Select all

#!/usr/bin/perl
#Dependency: libwww-perl, libjson-perl

###################################################
# Release notes
###################################################
#Version 0.1: First release (with very dirty code...)
# - switch on / off unit
# - report room temperature
# - report unit temperature set
# - report next unit update
 
###################################################
# INSTALLATION
###################################################
# Put scripts in Domoticz install dir under scripts
# Give execute write to the file
# Create dummy devices: 
#		- 1 switch for switch on/off device
#		     -> Action on scripts: script:///DOMOTICZ_DIR/scripts/melcloud.pl on MEL_DEVICENAME
#		     -> Action off scripts: script:///DOMOTICZ_DIR/scripts/melcloud.pl off MEL_DEVICENAME
#		- 1 temp for reporting room temperature
#		- 1 settemp for reporting temperature set on device
#		- 1 text for reporting next update hour
# Add cron entrie
# */10 * * * * /DOMOTICZ_DIR/scripts/melcloud.pl report 2>&1 >> /dev/null

use HTTP::Request::Common qw(POST GET);
use HTTP::Headers;
use LWP::UserAgent;
use JSON;     
use Data::Dumper;

#####################################################
# Configuration
#####################################################

my $Email = "EMAIL\@EMAIL";  # Email used to login to MELcloud
my $Password = "PASSWORD"; 		# Password used lo login to MELcloud
my $debug = 0;						# 0 = no debug, 1 = debug

my $domIP = "DOM_IP";			# Domoticz IP 
my $domPORT = "DOM_PORT";		# Domoticz PORT

my @devicesInfos;					# List of all devices. Add block for new devices
#Device 1
$devicesInfos{"NAME_ON_MELCLOUD"}{"idx_status"} = "88";	# IDX of status device (type switch)
$devicesInfos{"NAME_ON_MELCLOUD"}{"idx_temp"} = "89";		# IDX of temperature device (type temp)
$devicesInfos{"NAME_ON_MELCLOUD"}{"idx_update"} = "92";	# IDX of update time device (type text)
$devicesInfos{"NAME_ON_MELCLOUD"}{"idx_setTemp"} = "90";	# IDX of set temp device (type set point)

#Device n
$devicesInfos{"Bib"}{"idx_status"} = "104";
$devicesInfos{"Bib"}{"idx_temp"} = "97";
$devicesInfos{"Bib"}{"idx_update"} = "112";
$devicesInfos{"Bib"}{"idx_setTemp"} = "108";

##########################################################
#   Functions
##########################################################

sub debug {
		my ($msg) = @_;
		if ($debug) {
			print $msg."\n";
		}
}

sub getDOMDeviceStatus {
		my ($idx) = @_;
		my $url = "http://$domIP:$domPORT/json.htm?type=devices&rid=".$idx;
		my $ua = LWP::UserAgent->new();
		# Set our own user-agent string! 
		$ua->agent("Domoticz Gysmo");
		require HTTP::Request;
		$req = HTTP::Request->new(GET => $url);
		# Fire the cannon now ! 
		my $res = $ua->request($req);																						
		# Get the error back from the server if any 
		my $err = $res->status_line; 
		# Get server body text, $_ used in regexp on next line 
		$_ = $res->decoded_content;

		if (/Illegal Operation/ig || $err != 200) {
			return "Server returned error: $err\n";
		}
		else {
			$result = $1 if /(?:Status\"\ :)+(.*?),/s;
			debug("receive from domoticz: ".$result);
			return $result;
		}	
}

sub login {
	#Parameters
	my ($Email,$Password) = @_;
	#Variables
	my $AppVersion = "1.9.2.1";
	my $Language = "7";
	my $CaptchaChallenge = "";
	my $CaptchaResponse = "";
	my $Persist = "true";
	my $url = "https://app.melcloud.com/Mitsubishi.Wifi.Client/Login/ClientLogin";
	
	# set up the stuff 
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");

	# file.cgi should just return the data sent for this test 
	# These seem to be like <input type=text name=A value=$A > off a form... 
	my $req = POST $url, [
	AppVersion => "$AppVersion",
	CaptchaChallenge => "$CaptchaChallenge",
	CaptchaResponse => "$CaptchaResponse",
	Email => "$Email",
	Language => "$Language",
	Password => "$Password",
	Persist => "$Persist" 
	];

	# Fire the cannon now ! 
	my $res = $ua->request($req);																						

	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;

	if (/Illegal Operation/ig || $err != 200) {
		return "Server returned error: $err\n";
	}
	elsif(/\"ErrorId\":1/ig) {
		return "Bad password\n";
	}	
	elsif(/\"ErrorId\":null/ig) {
		$result  = $1 if /(?:ContextKey\":\")+(.*?)\"/s;
		debug ("context ID: ".$result);
		return $result;
	}
	else {
		return "Unknow error";
	}
}

sub getMELBuildingID {
	#Parameters
	my ($ContextKey,$devicename) = @_;
	#Variables
	my $url = "https://app.melcloud.com/Mitsubishi.Wifi.Client/User/ListDevices";
	# set up the stuff 
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	
	require HTTP::Request;
	$req = HTTP::Request->new(GET => $url);
	$req->header("X-MitsContextKey" => $ContextKey);
	# Fire the cannon now ! 
	my $res = $ua->request($req);																						

	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;
	my $decoded = JSON->new->utf8(0)->decode($_);
	my $result = "0";
	foreach my $building (@$decoded) {
		@build = @{$building->{'Structure'}{'Areas'}};
		foreach my $area (@build) {
				@devices = @{$area->{'Devices'}};
				foreach my $device (@devices) {
					if ( $device->{'DeviceName'} =~ $devicename) {
						$result =  $device->{'BuildingID'};
					}
				}
		}
	}
	if (/Illegal Operation/ig || $err != 200) {
		return "Server returned error: $err\n";
	}
	else {
	#	debug("Device ID: ".Dumper($decoded));
		return "$result";
	}
}

sub getMELDeviceID {
	#Parameters
	my ($ContextKey,$devicename) = @_;
	#Variables
	my $url = "https://app.melcloud.com/Mitsubishi.Wifi.Client/User/ListDevices";
	# set up the stuff 
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	
	require HTTP::Request;
	$req = HTTP::Request->new(GET => $url);
	$req->header("X-MitsContextKey" => $ContextKey);
	# Fire the cannon now ! 
	my $res = $ua->request($req);																						

	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;
	my $decoded = JSON->new->utf8(0)->decode($_);
	my $result = "0";
	foreach my $building (@$decoded) {
		@build = @{$building->{'Structure'}{'Areas'}};
		foreach my $area (@build) {
				@devices = @{$area->{'Devices'}};
				foreach my $device (@devices) {
					if ( $device->{'DeviceName'} =~ $devicename) {
						$result =  $device->{'DeviceID'};
					}
				}
		}
	}
	if (/Illegal Operation/ig || $err != 200) {
		return "Server returned error: $err\n";
	}
	else {
	#	debug("Device ID: ".Dumper($decoded));
		return "$result";
	}
}

sub listDevices {
	#Parameters
	my ($ContextKey) = @_;
	#Variables
	my $url = "https://app.melcloud.com/Mitsubishi.Wifi.Client/User/ListDevices";
	# set up the stuff 
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	
	require HTTP::Request;
	$req = HTTP::Request->new(GET => $url);
	$req->header("X-MitsContextKey" => $ContextKey);
	# Fire the cannon now ! 
	my $res = $ua->request($req);																						

	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;

	if (/Illegal Operation/ig || $err != 200) {
		return "Server returned error: $err\n";
	}
	else {
		$result = $_;
		debug("list devices: ".$result);
		return "$result";
	}
}

sub getAirConInfos {
	#Parameters
	my ($contextKey,$deviceID,$buildingID) = @_;
	#Variables
	my $url = 'https://app.melcloud.com/Mitsubishi.Wifi.Client/Device/Get?id=' . $deviceID . '&buildingID=' . $buildingID;
	#return $url;
	# set up the stuff 
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	
	require HTTP::Request;
	
	$req = HTTP::Request->new(GET => $url);
	$req->header("X-MitsContextKey" => $contextKey);

	# Fire the cannon now ! 
	my $res = $ua->request($req);																						

	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$json = $res->decoded_content;
	my $decoded = JSON->new->utf8(0)->decode($json);
 	if (/Illegal Operation/ig || $err != 200) {
		return "Server returned error: $err\n";
	}
	else {
		debug("device status : ". $decoded);
		return $decoded;
	}
}

sub setDomDeviceStatus {
	#Parameters
	my ($idDomDevice,$deviceInfos) = @_;
	#Variables
	$domStatus = getDOMDeviceStatus($idDomDevice);
	if ($deviceInfos->{'Power'} =~ /true/ && $domStatus =~ /"Off"/) {
		$switchcmd = "On";
	my $url = "http://$domIP:$domPORT/json.htm?type=command&param=switchlight&idx=".$idDomDevice."&switchcmd=".$switchcmd;
	debug("send to domoticz: ".$url);
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	
	require HTTP::Request;
	
	$req = HTTP::Request->new(GET => $url);
		# Fire the cannon now ! 
	my $res = $ua->request($req);																						

	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;

	if (/Illegal Operation/ig || $err != 200) {
		return "Server returned error: $err\n";
	}
	else {
		$result = $1 if /(?:status\"\ :)+(.*?),/s;
		debug("receive from domoticz: ".$result);
		return $result;
	}
	}
	elsif ($deviceInfos->{'Power'} =~ /false/ && $domStatus =~ /"On"/) {
		$switchcmd = "Off";
		my $url = "http://$domIP:$domPORT/json.htm?type=command&param=switchlight&idx=".$idDomDevice."&switchcmd=".$switchcmd;
	debug("send to domoticz: ".$url);
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	$ua->agent("Domoticz Gysmo");
	
	require HTTP::Request;
	
	$req = HTTP::Request->new(GET => $url);
		# Fire the cannon now ! 
	my $res = $ua->request($req);																						

	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;

	if (/Illegal Operation/ig || $err != 200) {
		return "Server returned error: $err\n";
	}
	else {
		$result = $1 if /(?:status\"\ :)+(.*?),/s;
		debug("receive from domoticz: ".$result);
		return $result;
	}
	}
	else {
			debug("send to domoticz: nothing to send");
	}
	
}

sub setDomDeviceTempRoom {
	#Parameters
	my ($idDomDevice,$deviceInfos) = @_;
	my $url = "http://$domIP:$domPORT/json.htm?type=command&param=udevice&idx=".$idDomDevice."&nvalue=0&svalue=".$deviceInfos->{'RoomTemperature'};
	debug("send to domoticz: ".$url);
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	require HTTP::Request;
	$req = HTTP::Request->new(GET => $url);
	# Fire the cannon now ! 
	my $res = $ua->request($req);																						
	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;
	if (/Illegal Operation/ig || $err != 200) {
		return "Server returned error: $err\n";
	}
	else {
		$result = $1 if /(?:status\"\ :)+(.*?),/s;
		debug("receive from domoticz: ".$result);
		return $result;
	}
}

sub setDomDeviceNextUpdate {
	#Parameters
	my ($idDomDevice,$deviceInfos) = @_;
	@time = split(/T/,$deviceInfos->{'NextCommunication'});
	my $url = "http://$domIP:$domPORT/json.htm?type=command&param=udevice&idx=".$idDomDevice."&nvalue=0&svalue=".$time[1];
	debug("send to domoticz: ".$url);
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	
	require HTTP::Request;
	
	$req = HTTP::Request->new(GET => $url);
		# Fire the cannon now ! 
	my $res = $ua->request($req);																						

	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;

	if (/Illegal Operation/ig || $err != 200) {
		return "Server returned error: $err\n";
	}
	else {
		$result = $1 if /(?:status\"\ :)+(.*?),/s;
		debug("receive from domoticz: ".$result);
		return $result;
	}
}


sub setDomDeviceTempClim {
	#Parameters
	my ($idDomDevice,$deviceInfos) = @_;
	my $url = "http://$domIP:$domPORT/json.htm?type=command&param=udevice&idx=".$idDomDevice."&nvalue=0&svalue=".$deviceInfos->{'SetTemperature'};
	debug("send to domoticz: ".$url);
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	
	require HTTP::Request;
	
	$req = HTTP::Request->new(GET => $url);
		# Fire the cannon now ! 
	my $res = $ua->request($req);																						

	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;

	if (/Illegal Operation/ig || $err != 200) {
		return "Server returned error: $err\n";
	}
	else {
		$result = $1 if /(?:status\"\ :)+(.*?),/s;
		debug("receive from domoticz: ".$result);
		return $result;
	}
}

sub setMELDeviceStatus {
	#Parameters
	my ($contextKey,$status,$deviceInfos,$idx) = @_;
	if($status =~ /on/ ) {
		$deviceInfos->{'Power'} = "true";
	}
	elsif($status =~ /off/ ) {
		$deviceInfos->{'Power'} = "false";
	}
	$deviceInfos->{'EffectiveFlags'} = "1";
	$deviceInfos->{'HasPendingCommand'} = "true";
	$json_device = JSON->new->utf8->encode($deviceInfos);
	#Variables
	my $url = 'https://app.melcloud.com/Mitsubishi.Wifi.Client/Device/SetAta';
	#return $url;
	# set up the stuff 
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	
	require HTTP::Request;
	$req = HTTP::Request->new(POST => $url);
	$req->header("X-MitsContextKey" => $contextKey);
	$req->header('content-type' => 'application/json');
	$req->content($json_device);
	# Fire the cannon now ! 
	my $res = $ua->request($req);																						

	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;
	my $decoded = JSON->new->utf8(0)->decode($_);
	if (/Illegal Operation/ig || $err != 200) {
		print "Server returned error: $err\n";
	}
	else {
		#Send next update time to domoticz
		setDomDeviceNextUpdate($idx,$decoded);
		@time = split(/T/,$decoded->{'NextCommunication'});
		debug("Update device : ".$time[1] );
		return $result;
	}
}

#####################################################
# Main program
#####################################################

#####################################################
# Init deviceID from Name
#####################################################
# TODO INIT  GET ALL DEVICES INFORMATION FROM MELCloud
$contextID = login($Email,$Password);
foreach my $name (keys %devicesInfos)  {
	$buildingID = getMELBuildingID($contextID,$name);
	$deviceID = getMELDeviceID($contextID,$name);
}

#####################################################
# Arguments
#####################################################
if ($ARGV[0] =~ /report/) {
	foreach my $name (keys %devicesInfos)  {
		debug("############################");
		debug("# Reporting device: " . $name ." #");
		debug("############################");
		$infosAirCon = getAirConInfos($contextID,$deviceID,$buildingID);
		setDomDeviceTempRoom($devicesInfos{$name}{"idx_temp"},$infosAirCon);
		setDomDeviceNextUpdate($devicesInfos{$name}{"idx_update"},$infosAirCon);
		setDomDeviceTempClim($devicesInfos{$name}{"idx_setTemp"},$infosAirCon);
		setDomDeviceStatus($devicesInfos{$name}{"idx_status"},$infosAirCon);
	}
}
elsif ($ARGV[0] =~ /on/ && exists $devicesInfos{$ARGV[1]}{'idx_status'}) {
	$infosAirCon = getAirConInfos($contextID,$deviceID,$buildingID);
	setMELDeviceStatus($contextID,"on",$infosAirCon,$devicesInfos{$ARGV[1]}{'idx_update'});
}
elsif ($ARGV[0] =~ /off/ && exists $devicesInfos{$ARGV[1]}{'idx_status'}) {
	$infosAirCon = getAirConInfos($contextID,$deviceID,$buildingID);
	setMELDeviceStatus($contextID,"off",$infosAirCon,$devicesInfos{$ARGV[1]}{'idx_update'});
}
elsif ($ARGV[0] =~ /help/) {
	print "report: send status of devices to domoticz. Use it for crontab\n";
	print "on DEVICENAME: switch on a device. Use it with Action On.\n";
	print "off DEVICENAME: switch off a device. Use it with Action Off\n";
	print "more to come...\n";
}
else {
	print "Nothing to do. Type help for help ;)\n";
}

You will find instructions in the beginning of the script.

My script connect to MELCloud website to get and change value to units.

There is a delay between switch on/off action and real switch on/off. The delay is reported to text device.

There is the same delay if you use Official MELCloud App or website.

For this first release, it only switch on/off unit an report some information.

I plan to add functionality like set temp, ventilation, cool or head and optimize code....

I am not a develloper so the code should be ugly like my english ;)

Re: Mitsubishi MAC-557IF-E control

Posted: Tuesday 04 August 2015 8:45
by ThinkPad
Nice!
Isn't it possible to control the unit directly over LAN? So that you bypass the Mitsubishi cloud service? Does it have a webserver? (Maybe run a portscan / nmap on the IP of the wifi-module).

That way there is (almost) no delay and you are not depending on a working internet connection. Have a look on the 'Daikin' script from Philos31 on this forum.

Re: [Perl] Control Mitsubishi MAC-557IF-E airconditioning

Posted: Tuesday 04 August 2015 11:01
by epierre
Hello,

is this cloud a simple auth or a double auto (OAuth) ?

Re: [Perl] Control Mitsubishi MAC-557IF-E airconditioning

Posted: Tuesday 04 August 2015 22:26
by gysmo38
My first try is to control directly the wireless device but i never manage to do it.
Here is my previous post : http://www.domoticz.com/forum/viewtopic.php?t=2472

For oauth, I'm not sure to understand.
I use login/password to auth to MELcloud website. For the moment, my script only connect Domoticz without auth.

Re: [Perl] Control Mitsubishi MAC-557IF-E airconditioning

Posted: Wednesday 05 August 2015 8:40
by epierre
hello,

oauth is used mainly by google to have a two steps authentification, I've not tried yet this way but this will be the industry path for API management

Re: [Perl] Control Mitsubishi MAC-557IF-E airconditioning

Posted: Wednesday 12 August 2015 16:27
by gysmo38
I think MELCloud do not allow this type of authentication.

Re: [Perl] Control Mitsubishi MAC-557IF-E airconditioning

Posted: Tuesday 15 September 2015 21:28
by bran2000
Sorry i used your script but i have an error to the line 160, this is the message error :

'"' expected, at character offset 4 (before "Success: false, Erro...") at ./melcloud.pl line 160.

this is the line 160 : my $res = $ua->request($req);

any idea how i can fix it
thanks

Re: [Perl] Control Mitsubishi MAC-557IF-E airconditioning

Posted: Friday 18 September 2015 22:46
by gysmo38
Hello,
I share with you the new version of my script.

My script can swith ON/OFF, change temperature, fan , vane and mode.

I need to create LUA scripts to send changement from thermostat.

Code: Select all

#!/usr/bin/perl
#Dependency: libwww-perl, libjson-perl

###################################################
# Release notes
###################################################
# Version 0.2:
# - add 2 hours for uptime time (for french)
# - add mode option
# - add fan option
# - add vane option (only vertical)
# - add settemp option
# Version 0.1: First release (with very dirty code...)
# - switch on / off unit
# - report room temperature
# - report unit temperature set
# - report next unit update

use HTTP::Request::Common qw(POST GET);
use HTTP::Headers;
use LWP::UserAgent;
use JSON;     
use Data::Dumper;

#####################################################
# Configuration
#####################################################

my $Email = "EMAIL\@EMAIL";  # Email used to login to MELcloud
my $Password = "PASSWORD"; 		# Password used lo login to MELcloud
my $debug = 0;						# 0 = no debug, 1 = debug

my $domIP = "DOM_IP";			# Domoticz IP 
my $domPORT = "DOM_PORT";		# Domoticz PORT

my @devicesInfos;					# List of all devices. Add block for new devices
#Device 1
$devicesInfos{"NAME_ON_MELCLOUD"}{"idx_status"} = "88";	# IDX of status device (type switch)
$devicesInfos{"NAME_ON_MELCLOUD"}{"idx_temp"} = "89";		# IDX of temperature device (type temp)
$devicesInfos{"NAME_ON_MELCLOUD"}{"idx_update"} = "92";	# IDX of update time device (type text)
$devicesInfos{"NAME_ON_MELCLOUD"}{"idx_setTemp"} = "90";	# IDX of set temp device (type set point)

#Device n
$devicesInfos{"Bib"}{"idx_status"} = "104";
$devicesInfos{"Bib"}{"idx_temp"} = "97";
$devicesInfos{"Bib"}{"idx_update"} = "112";
$devicesInfos{"Bib"}{"idx_setTemp"} = "108";


##########################################################
#   Functions
##########################################################

sub debug {
		my ($msg) = @_;
		if ($debug) {
			print $msg."\n";
		}
}

sub time_offset {
		my ($time,$offset) = @_;
		@split_time = split(/:/,$time);
		if($split_time[0] < 21) {
				$split_time[0] = $split_time[0] + 2;
		}
		elsif ($split_time[0] == 22) {
				$split_time[0] = 00;
		}
		elsif ($split_time[0] == 23) {
				$split_time[0] = 01;
		}
		return join(":",$split_time[0],$split_time[1],$split_time[2]);
}

sub getDOMDeviceStatus {
		my ($idx) = @_;
		my $url = "http://$domIP:$domPORT/json.htm?type=devices&rid=".$idx;
		my $ua = LWP::UserAgent->new();
		# Set our own user-agent string! 
		$ua->agent("Domoticz Gysmo");
		require HTTP::Request;
		$req = HTTP::Request->new(GET => $url);
		# Fire the cannon now ! 
		my $res = $ua->request($req);																						
		# Get the error back from the server if any 
		my $err = $res->status_line; 
		# Get server body text, $_ used in regexp on next line 
		$_ = $res->decoded_content;

		if (/Illegal Operation/ig || $err != 200) {
			return "Server returned error: $err\n";
		}
		else {
			$result = $1 if /(?:Status\"\ :)+(.*?),/s;
			debug("receive from domoticz: ".$result);
			return $result;
		}	
}

sub login {
	#Parameters
	my ($Email,$Password) = @_;
	#Variables
	my $AppVersion = "1.9.3.0";
	my $Language = "7";
	my $CaptchaChallenge = "";
	my $CaptchaResponse = "";
	my $Persist = "true";
	my $url = "https://app.melcloud.com/Mitsubishi.Wifi.Client/Login/ClientLogin";
	
	# set up the stuff 
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");

	# file.cgi should just return the data sent for this test 
	# These seem to be like <input type=text name=A value=$A > off a form... 
	my $req = POST $url, [
	AppVersion => "$AppVersion",
	CaptchaChallenge => "$CaptchaChallenge",
	CaptchaResponse => "$CaptchaResponse",
	Email => "$Email",
	Language => "$Language",
	Password => "$Password",
	Persist => "$Persist" 
	];

	# Fire the cannon now ! 
	my $res = $ua->request($req);																						

	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;

	if (/Illegal Operation/ig || $err != 200) {
		return "Server returned error: $err\n";
	}
	elsif(/\"ErrorId\":1/ig) {
		return "Bad password\n";
	}	
	elsif(/\"ErrorId\":null/ig) {
		$result  = $1 if /(?:ContextKey\":\")+(.*?)\"/s;
		debug ("context ID: ".$result);
		return $result;
	}
	else {
		return "Unknow error";
	}
}

sub getMELBuildingID {
	#Parameters
	my ($ContextKey,$devicename) = @_;
	#Variables
	my $url = "https://app.melcloud.com/Mitsubishi.Wifi.Client/User/ListDevices";
	# set up the stuff 
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	require HTTP::Request;
	$req = HTTP::Request->new(GET => $url);
	$req->header("X-MitsContextKey" => $ContextKey);
	# Fire the cannon now ! 
	my $res = $ua->request($req);																						
	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;
	my $decoded = JSON->new->utf8(0)->decode($_);
	my $result = "0";
	foreach my $building (@$decoded) {
		@build = @{$building->{'Structure'}{'Areas'}};
		foreach my $area (@build) {
				@devices = @{$area->{'Devices'}};
				foreach my $device (@devices) {
					if ( $device->{'DeviceName'} =~ $devicename) {
						$result =  $device->{'BuildingID'};
					}
				}
		}
	}
	if (/Illegal Operation/ig || $err != 200) {
		return "Server returned error: $err\n";
	}
	else {
	#	debug("Device ID: ".Dumper($decoded));
		return "$result";
	}
}

sub getMELDeviceID {
	#Parameters
	my ($ContextKey,$devicename) = @_;
	#Variables
	my $url = "https://app.melcloud.com/Mitsubishi.Wifi.Client/User/ListDevices";
	# set up the stuff 
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	
	require HTTP::Request;
	$req = HTTP::Request->new(GET => $url);
	$req->header("X-MitsContextKey" => $ContextKey);
	# Fire the cannon now ! 
	my $res = $ua->request($req);																						

	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;
	my $decoded = JSON->new->utf8(0)->decode($_);
	my $result = "0";
	foreach my $building (@$decoded) {
		@build = @{$building->{'Structure'}{'Areas'}};
		foreach my $area (@build) {
				@devices = @{$area->{'Devices'}};
				foreach my $device (@devices) {
					if ( $device->{'DeviceName'} =~ $devicename) {
						
						$result =  $device->{'DeviceID'};
					}
				}
		}
	}
	if (/Illegal Operation/ig || $err != 200) {
		return "Server returned error: $err\n";
	}
	else {
	#	debug("Device ID: ".Dumper($decoded));
		return "$result";
	}
}

sub listDevices {
	#Parameters
	my ($ContextKey) = @_;
	#Variables
	my $url = "https://app.melcloud.com/Mitsubishi.Wifi.Client/User/ListDevices";
	# set up the stuff 
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	
	require HTTP::Request;
	$req = HTTP::Request->new(GET => $url);
	$req->header("X-MitsContextKey" => $ContextKey);
	# Fire the cannon now ! 
	my $res = $ua->request($req);																						

	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;

	if (/Illegal Operation/ig || $err != 200) {
		return "Server returned error: $err\n";
	}
	else {
		$result = $_;
		debug("list devices: ".$result);
		return "$result";
	}
}

sub getAirConInfos {
	#Parameters
	my ($contextKey,$deviceID,$buildingID) = @_;
	#Variables
	my $url = 'https://app.melcloud.com/Mitsubishi.Wifi.Client/Device/Get?id=' . $deviceID . '&buildingID=' . $buildingID;
	#return $url;
	# set up the stuff 
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	
	require HTTP::Request;
	
	$req = HTTP::Request->new(GET => $url);
	$req->header("X-MitsContextKey" => $contextKey);

	# Fire the cannon now ! 
	my $res = $ua->request($req);																						

	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$json = $res->decoded_content;
	my $decoded = JSON->new->utf8(0)->decode($json);
 	if (/Illegal Operation/ig || $err != 200) {
		return "Server returned error: $err\n";
	}
	else {
		debug("device status : ". $decoded);
		return $decoded;
	}
}

sub setDomDeviceStatus {
	#Parameters
	my ($idDomDevice,$deviceInfos) = @_;
	#Variables
	$domStatus = getDOMDeviceStatus($idDomDevice);
	if ($deviceInfos->{'Power'} =~ /true/ && $domStatus =~ /"Off"/) {
		$switchcmd = "On";
	my $url = "http://$domIP:$domPORT/json.htm?type=command&param=switchlight&idx=".$idDomDevice."&switchcmd=".$switchcmd;
	debug("send to domoticz: ".$url);
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	
	require HTTP::Request;
	
	$req = HTTP::Request->new(GET => $url);
		# Fire the cannon now ! 
	my $res = $ua->request($req);																						

	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;

	if (/Illegal Operation/ig || $err != 200) {
		return "Server returned error: $err\n";
	}
	else {
		$result = $1 if /(?:status\"\ :)+(.*?),/s;
		debug("receive from domoticz: ".$result);
		return $result;
	}
	}
	elsif ($deviceInfos->{'Power'} =~ /false/ && $domStatus =~ /"On"/) {
		$switchcmd = "Off";
		my $url = "http://$domIP:$domPORT/json.htm?type=command&param=switchlight&idx=".$idDomDevice."&switchcmd=".$switchcmd;
		debug("send to domoticz: ".$url);
		my $ua = LWP::UserAgent->new();
		# Set our own user-agent string! 
		$ua->agent("Domoticz Gysmo");
	
	require HTTP::Request;
	
	$req = HTTP::Request->new(GET => $url);
		# Fire the cannon now ! 
	my $res = $ua->request($req);																						

	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;

	if (/Illegal Operation/ig || $err != 200) {
		return "Server returned error: $err\n";
	}
	else {
		$result = $1 if /(?:status\"\ :)+(.*?),/s;
		debug("receive from domoticz: ".$result);
		return $result;
	}
	}
	else {
			debug("send to domoticz: nothing to send");
	}
	
}

sub setDomDeviceTempRoom {
	#Parameters
	my ($idDomDevice,$deviceInfos) = @_;
	my $url = "http://$domIP:$domPORT/json.htm?type=command&param=udevice&idx=".$idDomDevice."&nvalue=0&svalue=".$deviceInfos->{'RoomTemperature'};
	debug("send to domoticz: ".$url);
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	require HTTP::Request;
	$req = HTTP::Request->new(GET => $url);
	# Fire the cannon now ! 
	my $res = $ua->request($req);																						
	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;
	if (/Illegal Operation/ig || $err != 200) {
		return "Server returned error: $err\n";
	}
	else {
		$result = $1 if /(?:status\"\ :)+(.*?),/s;
		debug("receive from domoticz: ".$result);
		return $result;
	}
}

sub setDomDeviceNextUpdate {
	#Parameters
	my ($idDomDevice,$deviceInfos) = @_;
	@time = split(/T/,$deviceInfos->{'NextCommunication'});
	my $url = "http://$domIP:$domPORT/json.htm?type=command&param=udevice&idx=".$idDomDevice."&nvalue=0&svalue=".time_offset($time[1],2);
	debug("send to domoticz: ".$url);
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	
	require HTTP::Request;
	
	$req = HTTP::Request->new(GET => $url);
		# Fire the cannon now ! 
	my $res = $ua->request($req);																						

	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;

	if (/Illegal Operation/ig || $err != 200) {
		return "Server returned error: $err\n";
	}
	else {
		$result = $1 if /(?:status\"\ :)+(.*?),/s;
		debug("receive from domoticz: ".$result);
		return $result;
	}
}


sub setDomDeviceTempClim {
	#Parameters
	my ($idDomDevice,$deviceInfos) = @_;
	my $url = "http://$domIP:$domPORT/json.htm?type=command&param=udevice&idx=".$idDomDevice."&nvalue=0&svalue=".$deviceInfos->{'SetTemperature'};
	debug("send to domoticz: ".$url);
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	
	require HTTP::Request;
	
	$req = HTTP::Request->new(GET => $url);
		# Fire the cannon now ! 
	my $res = $ua->request($req);																						

	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;

	if (/Illegal Operation/ig || $err != 200) {
		return "Server returned error: $err\n";
	}
	else {
		$result = $1 if /(?:status\"\ :)+(.*?),/s;
		debug("receive from domoticz: ".$result);
		return $result;
	}
}

sub setMELDevicePower {
	#Parameters
	my ($contextKey,$status,$deviceInfos,$idx) = @_;
	if($status =~ /on/ ) {
		$deviceInfos->{'Power'} = "true";
	}
	elsif($status =~ /off/ ) {
		$deviceInfos->{'Power'} = "false";
	}
	$deviceInfos->{'EffectiveFlags'} = "1";
	$deviceInfos->{'HasPendingCommand'} = "true";
	$json_device = JSON->new->utf8->encode($deviceInfos);
	#Variables
	my $url = 'https://app.melcloud.com/Mitsubishi.Wifi.Client/Device/SetAta';
	#return $url;
	# set up the stuff 
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	
	require HTTP::Request;
	$req = HTTP::Request->new(POST => $url);
	$req->header("X-MitsContextKey" => $contextKey);
	$req->header('content-type' => 'application/json');
	$req->content($json_device);
	# Fire the cannon now ! 
	my $res = $ua->request($req);																						

	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;
	debug($_);
	if (/Illegal Operation/ig || $err != 200) {
		print "Server returned error: $err\n";
	}
	else {
		my $decoded = JSON->new->utf8(0)->decode($_);
		#Send next update time to domoticz
		setDomDeviceNextUpdate($idx,$decoded);
		@time = split(/T/,$decoded->{'NextCommunication'});
		debug("Update device : ".time_offset($time[1],2) );
		return $result;
	}
}

sub setMELDeviceFan {
	#Parameters
	my ($contextKey,$temp,$deviceInfos,$idx) = @_;
	$deviceInfos->{'SetFanSpeed'} = $temp;
	$deviceInfos->{'EffectiveFlags'} = "8";
	$deviceInfos->{'HasPendingCommand'} = "true";
	$json_device = JSON->new->utf8->encode($deviceInfos);
	#Variables
	my $url = 'https://app.melcloud.com/Mitsubishi.Wifi.Client/Device/SetAta';
	# set up the stuff 
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	require HTTP::Request;
	$req = HTTP::Request->new(POST => $url);
	$req->header("X-MitsContextKey" => $contextKey);
	$req->header('content-type' => 'application/json');
	$req->content($json_device);
	# Fire the cannon now ! 
	my $res = $ua->request($req);																						
	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;
	if (/Illegal Operation/ig || $err != 200) {
		print "Server returned error: $err\n";
	}
	else {
		my $decoded = JSON->new->utf8(0)->decode($_);
		#Send next update time to domoticz
		setDomDeviceNextUpdate($idx,$decoded);
		#######################
		# Futur fonction time
		#######################
		@time = split(/T/,$decoded->{'NextCommunication'});
		debug("Update device : ".time_offset($time[1],2) );
		return $result;
	}
}

sub setMELDeviceMode {
	#Parameters
	my ($contextKey,$mode,$deviceInfos,$idx) = @_;
	# Mode value : 1 warm, 2 dry, 3 cool, 7 vent, 8 auto
	if ($mode =~ warm) {
		$deviceInfos->{'OperationMode'} = 1;
	}
	elsif ($mode =~ dry) {
		$deviceInfos->{'OperationMode'} = 2;
	}
	elsif ($mode =~ cool) {
		$deviceInfos->{'OperationMode'} = 3;
	}
	elsif ($mode =~ vent) {
		$deviceInfos->{'OperationMode'} = 7;
	}
	elsif ($mode =~ auto) {
		$deviceInfos->{'OperationMode'} = 8;
	}	
	$deviceInfos->{'EffectiveFlags'} = "6";
	$deviceInfos->{'HasPendingCommand'} = "true";
	$json_device = JSON->new->utf8->encode($deviceInfos);
	#Variables
	my $url = 'https://app.melcloud.com/Mitsubishi.Wifi.Client/Device/SetAta';
	# set up the stuff 
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	require HTTP::Request;
	$req = HTTP::Request->new(POST => $url);
	$req->header("X-MitsContextKey" => $contextKey);
	$req->header('content-type' => 'application/json');
	$req->content($json_device);
	# Fire the cannon now ! 
	my $res = $ua->request($req);																						
	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;
	if (/Illegal Operation/ig || $err != 200) {
		print "Server returned error: $err\n";
	}
	else {
		my $decoded = JSON->new->utf8(0)->decode($_);
		#Send next update time to domoticz
		setDomDeviceNextUpdate($idx,$decoded);
		#######################
		# Futur fonction time
		#######################
		@time = split(/T/,$decoded->{'NextCommunication'});
		debug("Update device : ".time_offset($time[1],2) );
		return $result;
	}
}

sub setMELDeviceVane {
	#Parameters
	my ($contextKey,$vane,$deviceInfos,$idx) = @_;
	$deviceInfos->{'VaneVertical'} = $vane;
	$deviceInfos->{'EffectiveFlags'} = "16";
	$deviceInfos->{'HasPendingCommand'} = "true";
	$json_device = JSON->new->utf8->encode($deviceInfos);
	#Variables
	my $url = 'https://app.melcloud.com/Mitsubishi.Wifi.Client/Device/SetAta';
	# set up the stuff 
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	require HTTP::Request;
	$req = HTTP::Request->new(POST => $url);
	$req->header("X-MitsContextKey" => $contextKey);
	$req->header('content-type' => 'application/json');
	$req->content($json_device);
	# Fire the cannon now ! 
	my $res = $ua->request($req);																						
	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;
	if (/Illegal Operation/ig || $err != 200) {
		print "Server returned error: $err\n";
	}
	else {
		my $decoded = JSON->new->utf8(0)->decode($_);
		#Send next update time to domoticz
		setDomDeviceNextUpdate($idx,$decoded);
		#######################
		# Futur fonction time
		#######################
		@time = split(/T/,$decoded->{'NextCommunication'});
		debug("Update device : ".time_offset($time[1],2) );
		return $result;
	}
}

sub setMELDeviceTemp {
	#Parameters
	my ($contextKey,$temp,$deviceInfos,$idx) = @_;
	$deviceInfos->{'SetTemperature'} = $temp;
	$deviceInfos->{'EffectiveFlags'} = "4";
	$deviceInfos->{'HasPendingCommand'} = "true";
	$json_device = JSON->new->utf8->encode($deviceInfos);
	#Variables
	my $url = 'https://app.melcloud.com/Mitsubishi.Wifi.Client/Device/SetAta';
	# set up the stuff 
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	require HTTP::Request;
	$req = HTTP::Request->new(POST => $url);
	$req->header("X-MitsContextKey" => $contextKey);
	$req->header('content-type' => 'application/json');
	$req->content($json_device);
	# Fire the cannon now ! 
	my $res = $ua->request($req);																						
	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;
	if (/Illegal Operation/ig || $err != 200) {
		print "Server returned error: $err\n";
	}
	else {
		my $decoded = JSON->new->utf8(0)->decode($_);
		#Send next update time to domoticz
		setDomDeviceNextUpdate($idx,$decoded);
		#######################
		# Futur fonction time
		#######################
		@time = split(/T/,$decoded->{'NextCommunication'});
		debug("Update device : ".time_offset($time[1],2) );
		return $result;
	}
}

sub init_mel {
	#Parameters
	my ($search_name) = @_;
	$contextID = login($Email,$Password);
	foreach my $name (keys %devicesInfos)  {
		if ( $name =~ $search_name ) {
			$buildingID = getMELBuildingID($contextID,$name);
			$deviceID = getMELDeviceID($contextID,$name);
		}
	}
}

#####################################################
# Main program
#####################################################


#####################################################
# Arguments
#####################################################
if ($ARGV[0] =~ /report/) {
	$contextID = login($Email,$Password);
	foreach my $name (keys %devicesInfos)  {
		$buildingID = getMELBuildingID($contextID,$name);
		$deviceID = getMELDeviceID($contextID,$name);
		debug("############################");
		debug("# Reporting device: " . $name ." #");
		debug("############################");
		$infosAirCon = getAirConInfos($contextID,$deviceID,$buildingID);
		setDomDeviceTempRoom($devicesInfos{$name}{"idx_temp"},$infosAirCon);
		setDomDeviceNextUpdate($devicesInfos{$name}{"idx_update"},$infosAirCon);
		setDomDeviceTempClim($devicesInfos{$name}{"idx_setTemp"},$infosAirCon);
		setDomDeviceStatus($devicesInfos{$name}{"idx_status"},$infosAirCon);
	}
}
elsif ($ARGV[0] =~ /test/) {
	init_mel($ARGV[1]);
	debug("Send command to building:" . $buildingID);
	debug("Send command to device:" . $deviceID);
	
}

elsif ($ARGV[0] =~ /temp/ && exists $devicesInfos{$ARGV[2]}{'idx_status'}) {
	init_mel($ARGV[2]);
	$infosAirCon = getAirConInfos($contextID,$deviceID,$buildingID);
	setMELDeviceTemp($contextID,$ARGV[1],$infosAirCon,$devicesInfos{$ARGV[2]}{'idx_update'});
}
elsif ($ARGV[0] =~ /fan/ && exists $devicesInfos{$ARGV[2]}{'idx_status'}) {
	init_mel($ARGV[2]);
	debug("Send commande to device:" . $buildingID);
	$infosAirCon = getAirConInfos($contextID,$deviceID,$buildingID);
	setMELDeviceFan($contextID,$ARGV[1],$infosAirCon,$devicesInfos{$ARGV[2]}{'idx_update'});
}
elsif ($ARGV[0] =~ /power/ && exists $devicesInfos{$ARGV[2]}{'idx_status'}) {
	init_mel($ARGV[2]);
	$infosAirCon = getAirConInfos($contextID,$deviceID,$buildingID);
	setMELDevicePower($contextID,$ARGV[1],$infosAirCon,$devicesInfos{$ARGV[2]}{'idx_update'});
}
elsif ($ARGV[0] =~ /mode/ && exists $devicesInfos{$ARGV[2]}{'idx_status'}) {
	init_mel($ARGV[2]);
	$infosAirCon = getAirConInfos($contextID,$deviceID,$buildingID);
	setMELDeviceMode($contextID,$ARGV[1],$infosAirCon,$devicesInfos{$ARGV[2]}{'idx_update'});
}
elsif ($ARGV[0] =~ /vane/ && exists $devicesInfos{$ARGV[2]}{'idx_status'}) {
	init_mel($ARGV[2]);
	$infosAirCon = getAirConInfos($contextID,$deviceID,$buildingID);
	setMELDeviceVane($contextID,$ARGV[1],$infosAirCon,$devicesInfos{$ARGV[2]}{'idx_update'});
}
elsif ($ARGV[0] =~ /help/) {
	print "report: send status of devices to domoticz. Use it for crontab\n";
	print "power on/off DEVICENAME: power on or off a device.\n";
	print "mode modename DEVICENAME: choose mode warm,dry,cool,vent or auto";
	print "temp T° DEVICENAME: set temperature device. \n";
	print "fan FAN_SPEED DEVICENAME: set fan speed of the device. \n";
	print "vane VANE_POS DEVICENAME: set van position to 1 - 5, 0 to auto and 7 to move . \n";
	print "more to come...\n";
}
else {
	print "Nothing to do. Type help for help ;)\n";
}
For your problem, maybe it is a problem with variables login ans password.

If you use special caracters, you need escape caracter before. For example my $Email = "toot\@titi.com"

Let me known if it correct the problem.

Re: [Perl] Control Mitsubishi MAC-557IF-E airconditioning

Posted: Sunday 03 January 2016 14:35
by bran2000
Hi,
i used your new script, the script is not running, any idea ? Someting is not working with this one.
i tried the original script without modification and the one where i modified the settings about idx, account ... always the same result.
pi@DomoticzSam ~/domoticz/scripts $ perl mitsu.pl
Nothing to do. Type help for help ;)

Thanks

Re: [Perl] Control Mitsubishi MAC-557IF-E airconditioning

Posted: Sunday 03 January 2016 20:18
by gysmo38
Hello,

You need to put some arguments:

For example if you want to switch on a module use this commande: perl melcloud.pl power on Salon where Salon is the name of your module in Melcloud website.

If you want to see all arguments user perl melcloud.pl help

I write a new version with all options : mode cool/warm, on/off, set temperature, get temperature, H Van inclinaison and fan speed.

I use my script for severals months, it work well.

Here is new code:

Code: Select all

#!/usr/bin/perl
#Dependency: libwww-perl, libjson-perl

###################################################
# Release notes
###################################################
# Version 0.2:
# - add 2 hours for uptime time (for french)
# - add mode option
# - add fan option
# - add vane option (only vertical)
# - add settemp option
# Version 0.1: First release (with very dirty code...)
# - switch on / off unit
# - report room temperature
# - report unit temperature set
# - report next unit update

use HTTP::Request::Common qw(POST GET);
use HTTP::Headers;
use LWP::UserAgent;
use JSON;     
use Data::Dumper;

#####################################################
# Configuration
#####################################################

my $Email = "EMAIL\@EMAIL";  # Email used to login to MELcloud
my $Password = "PASSWORD"; 		# Password used lo login to MELcloud
my $debug = 0;						# 0 = no debug, 1 = debug

my $domIP = "DOM_IP";			# Domoticz IP 
my $domPORT = "DOM_PORT";		# Domoticz PORT

my @devicesInfos;					# List of all devices. Add block for new devices
#Device 1
$devicesInfos{"NAME_ON_MELCLOUD"}{"idx_status"} = "88";	# IDX of status device (type switch)
$devicesInfos{"NAME_ON_MELCLOUD"}{"idx_temp"} = "89";		# IDX of temperature device (type temp)
$devicesInfos{"NAME_ON_MELCLOUD"}{"idx_update"} = "92";	# IDX of update time device (type text)
$devicesInfos{"NAME_ON_MELCLOUD"}{"idx_setTemp"} = "90";	# IDX of set temp device (type set point)
$devicesInfos{"NAME_ON_MELCLOUD"}{"idx_modeCool"} = "126"; # IDX of mode cool (type switch)
$devicesInfos{"NAME_ON_MELCLOUD"}{"idx_modeWarm"} = "125"; # IDX of mode warm (type switch)

#Device n
$devicesInfos{"Parents"}{"idx_status"} = "101";
$devicesInfos{"Parents"}{"idx_temp"} = "94";
$devicesInfos{"Parents"}{"idx_update"} = "109";
$devicesInfos{"Parents"}{"idx_setTemp"} = "105";
$devicesInfos{"Parents"}{"idx_modeCool"} = "126";
$devicesInfos{"Parents"}{"idx_modeWarm"} = "125";


##########################################################
#   Functions
##########################################################

sub debug {
		my ($msg) = @_;
		if ($debug) {
			print $msg."\n";
		}
}

sub time_offset {
		my ($time,$offset) = @_;
		@split_time = split(/:/,$time);
		if($split_time[0] < 21) {
				$split_time[0] = $split_time[0] + 2;
		}
		elsif ($split_time[0] == 22) {
				$split_time[0] = 00;
		}
		elsif ($split_time[0] == 23) {
				$split_time[0] = 01;
		}
		return join(":",$split_time[0],$split_time[1],$split_time[2]);
}

sub getDOMDeviceStatus {
		my ($idx) = @_;
		my $url = "http://$domIP:$domPORT/json.htm?type=devices&rid=".$idx;
		my $ua = LWP::UserAgent->new();
		# Set our own user-agent string! 
		$ua->agent("Domoticz Gysmo");
		require HTTP::Request;
		$req = HTTP::Request->new(GET => $url);
		# Fire the cannon now ! 
		my $res = $ua->request($req);																						
		# Get the error back from the server if any 
		my $err = $res->status_line; 
		# Get server body text, $_ used in regexp on next line 
		$_ = $res->decoded_content;

		if (/Illegal Operation/ig || $err != 200) {
			return "Server returned error: $err\n";
		}
		else {
			$result = $1 if /(?:Status\"\ :)+(.*?),/s;
			debug("receive from domoticz: ".$result);
			return $result;
		}	
}

sub login {
	#Parameters
	my ($Email,$Password) = @_;
	#Variables
	my $AppVersion = "1.9.3.0";
	my $Language = "7";
	my $CaptchaChallenge = "";
	my $CaptchaResponse = "";
	my $Persist = "true";
	my $url = "https://app.melcloud.com/Mitsubishi.Wifi.Client/Login/ClientLogin";
	
	# set up the stuff 
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");

	# file.cgi should just return the data sent for this test 
	# These seem to be like <input type=text name=A value=$A > off a form... 
	my $req = POST $url, [
	AppVersion => "$AppVersion",
	CaptchaChallenge => "$CaptchaChallenge",
	CaptchaResponse => "$CaptchaResponse",
	Email => "$Email",
	Language => "$Language",
	Password => "$Password",
	Persist => "$Persist" 
	];

	# Fire the cannon now ! 
	my $res = $ua->request($req);																						

	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;

	if (/Illegal Operation/ig || $err != 200) {
		return "Server returned error: $err\n";
	}
	elsif(/\"ErrorId\":1/ig) {
		return "Bad password\n";
	}	
	elsif(/\"ErrorId\":null/ig) {
		$result  = $1 if /(?:ContextKey\":\")+(.*?)\"/s;
		debug ("context ID: ".$result);
		return $result;
	}
	else {
		return "Unknow error";
	}
}

sub getMELBuildingID {
	#Parameters
	my ($ContextKey,$devicename) = @_;
	#Variables
	my $url = "https://app.melcloud.com/Mitsubishi.Wifi.Client/User/ListDevices";
	# set up the stuff 
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	require HTTP::Request;
	$req = HTTP::Request->new(GET => $url);
	$req->header("X-MitsContextKey" => $ContextKey);
	# Fire the cannon now ! 
	my $res = $ua->request($req);																						
	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;
	my $decoded = JSON->new->utf8(0)->decode($_);
	my $result = "0";
	foreach my $building (@$decoded) {
		@build = @{$building->{'Structure'}{'Areas'}};
		foreach my $area (@build) {
				@devices = @{$area->{'Devices'}};
				foreach my $device (@devices) {
					if ( $device->{'DeviceName'} =~ $devicename) {
						$result =  $device->{'BuildingID'};
					}
				}
		}
	}
	if (/Illegal Operation/ig || $err != 200) {
		return "Server returned error: $err\n";
	}
	else {
	#	debug("Device ID: ".Dumper($decoded));
		return "$result";
	}
}

sub getMELDeviceID {
	#Parameters
	my ($ContextKey,$devicename) = @_;
	#Variables
	my $url = "https://app.melcloud.com/Mitsubishi.Wifi.Client/User/ListDevices";
	# set up the stuff 
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	
	require HTTP::Request;
	$req = HTTP::Request->new(GET => $url);
	$req->header("X-MitsContextKey" => $ContextKey);
	# Fire the cannon now ! 
	my $res = $ua->request($req);																						

	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;
	my $decoded = JSON->new->utf8(0)->decode($_);
	my $result = "0";
	foreach my $building (@$decoded) {
		@build = @{$building->{'Structure'}{'Areas'}};
		foreach my $area (@build) {
				@devices = @{$area->{'Devices'}};
				foreach my $device (@devices) {
					if ( $device->{'DeviceName'} =~ $devicename) {
						
						$result =  $device->{'DeviceID'};
					}
				}
		}
	}
	if (/Illegal Operation/ig || $err != 200) {
		return "Server returned error: $err\n";
	}
	else {
	#	debug("Device ID: ".Dumper($decoded));
		return "$result";
	}
}

sub listDevices {
	#Parameters
	my ($ContextKey) = @_;
	#Variables
	my $url = "https://app.melcloud.com/Mitsubishi.Wifi.Client/User/ListDevices";
	# set up the stuff 
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	
	require HTTP::Request;
	$req = HTTP::Request->new(GET => $url);
	$req->header("X-MitsContextKey" => $ContextKey);
	# Fire the cannon now ! 
	my $res = $ua->request($req);																						

	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;

	if (/Illegal Operation/ig || $err != 200) {
		return "Server returned error: $err\n";
	}
	else {
		$result = $_;
		debug("list devices: ".$result);
		return "$result";
	}
}

sub getAirConInfos {
	#Parameters
	my ($contextKey,$deviceID,$buildingID) = @_;
	#Variables
	my $url = 'https://app.melcloud.com/Mitsubishi.Wifi.Client/Device/Get?id=' . $deviceID . '&buildingID=' . $buildingID;
	#return $url;
	# set up the stuff 
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	
	require HTTP::Request;
	
	$req = HTTP::Request->new(GET => $url);
	$req->header("X-MitsContextKey" => $contextKey);

	# Fire the cannon now ! 
	my $res = $ua->request($req);																						

	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$json = $res->decoded_content;
	my $decoded = JSON->new->utf8(0)->decode($json);
 	if (/Illegal Operation/ig || $err != 200) {
		return "Server returned error: $err\n";
	}
	else {
		debug("device status : ". $decoded);
		return $decoded;
	}
}

sub setDomDeviceStatus {
	#Parameters
	my ($idDomDevice,$deviceInfos) = @_;
	#Variables
	$domStatus = getDOMDeviceStatus($idDomDevice);
	if ($deviceInfos->{'Power'} =~ /true/ && $domStatus =~ /"Off"/) {
		$switchcmd = "On";
	my $url = "http://$domIP:$domPORT/json.htm?type=command&param=switchlight&idx=".$idDomDevice."&switchcmd=".$switchcmd;
	debug("send to domoticz: ".$url);
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	
	require HTTP::Request;
	
	$req = HTTP::Request->new(GET => $url);
		# Fire the cannon now ! 
	my $res = $ua->request($req);																						

	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;

	if (/Illegal Operation/ig || $err != 200) {
		return "Server returned error: $err\n";
	}
	else {
		$result = $1 if /(?:status\"\ :)+(.*?),/s;
		debug("receive from domoticz: ".$result);
		return $result;
	}
	}
	elsif ($deviceInfos->{'Power'} =~ /false/ && $domStatus =~ /"On"/) {
		$switchcmd = "Off";
		my $url = "http://$domIP:$domPORT/json.htm?type=command&param=switchlight&idx=".$idDomDevice."&switchcmd=".$switchcmd;
		debug("send to domoticz: ".$url);
		my $ua = LWP::UserAgent->new();
		# Set our own user-agent string! 
		$ua->agent("Domoticz Gysmo");
	
	require HTTP::Request;
	
	$req = HTTP::Request->new(GET => $url);
		# Fire the cannon now ! 
	my $res = $ua->request($req);																						

	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;

	if (/Illegal Operation/ig || $err != 200) {
		return "Server returned error: $err\n";
	}
	else {
		$result = $1 if /(?:status\"\ :)+(.*?),/s;
		debug("receive from domoticz: ".$result);
		return $result;
	}
	}
	else {
			debug("send to domoticz: nothing to send");
	}
	
}

sub setDomDeviceTempRoom {
	#Parameters
	my ($idDomDevice,$deviceInfos) = @_;
	my $url = "http://$domIP:$domPORT/json.htm?type=command&param=udevice&idx=".$idDomDevice."&nvalue=0&svalue=".$deviceInfos->{'RoomTemperature'};
	debug("send to domoticz: ".$url);
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	require HTTP::Request;
	$req = HTTP::Request->new(GET => $url);
	# Fire the cannon now ! 
	my $res = $ua->request($req);																						
	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;
	if (/Illegal Operation/ig || $err != 200) {
		return "Server returned error: $err\n";
	}
	else {
		$result = $1 if /(?:status\"\ :)+(.*?),/s;
		debug("receive from domoticz: ".$result);
		return $result;
	}
}

sub setDomDeviceNextUpdate {
	#Parameters
	my ($idDomDevice,$deviceInfos) = @_;
	@time = split(/T/,$deviceInfos->{'NextCommunication'});
	my $url = "http://$domIP:$domPORT/json.htm?type=command&param=udevice&idx=".$idDomDevice."&nvalue=0&svalue=".time_offset($time[1],2);
	debug("send to domoticz: ".$url);
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	
	require HTTP::Request;
	
	$req = HTTP::Request->new(GET => $url);
		# Fire the cannon now ! 
	my $res = $ua->request($req);																						

	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;

	if (/Illegal Operation/ig || $err != 200) {
		return "Server returned error: $err\n";
	}
	else {
		$result = $1 if /(?:status\"\ :)+(.*?),/s;
		debug("receive from domoticz: ".$result);
		return $result;
	}
}


sub setDomDeviceTempClim {
	#Parameters
	my ($idDomDevice,$deviceInfos) = @_;
	my $url = "http://$domIP:$domPORT/json.htm?type=command&param=udevice&idx=".$idDomDevice."&nvalue=0&svalue=".$deviceInfos->{'SetTemperature'};
	debug("send to domoticz: ".$url);
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	
	require HTTP::Request;
	
	$req = HTTP::Request->new(GET => $url);
		# Fire the cannon now ! 
	my $res = $ua->request($req);																						

	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;

	if (/Illegal Operation/ig || $err != 200) {
		return "Server returned error: $err\n";
	}
	else {
		$result = $1 if /(?:status\"\ :)+(.*?),/s;
		debug("receive from domoticz: ".$result);
		return $result;
	}
}

sub setMELDevicePower {
	#Parameters
	my ($contextKey,$status,$deviceInfos,$idx) = @_;
	if($status =~ /on/ ) {
		$deviceInfos->{'Power'} = "true";
	}
	elsif($status =~ /off/ ) {
		$deviceInfos->{'Power'} = "false";
	}
	$deviceInfos->{'EffectiveFlags'} = "1";
	$deviceInfos->{'HasPendingCommand'} = "true";
	$json_device = JSON->new->utf8->encode($deviceInfos);
	#Variables
	my $url = 'https://app.melcloud.com/Mitsubishi.Wifi.Client/Device/SetAta';
	#return $url;
	# set up the stuff 
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	
	require HTTP::Request;
	$req = HTTP::Request->new(POST => $url);
	$req->header("X-MitsContextKey" => $contextKey);
	$req->header('content-type' => 'application/json');
	$req->content($json_device);
	# Fire the cannon now ! 
	my $res = $ua->request($req);																						

	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;
	debug($_);
	if (/Illegal Operation/ig || $err != 200) {
		print "Server returned error: $err\n";
	}
	else {
		my $decoded = JSON->new->utf8(0)->decode($_);
		#Send next update time to domoticz
		setDomDeviceNextUpdate($idx,$decoded);
		@time = split(/T/,$decoded->{'NextCommunication'});
		debug("Update device : ".time_offset($time[1],2) );
		return $result;
	}
}

sub setMELDeviceFan {
	#Parameters
	my ($contextKey,$temp,$deviceInfos,$idx) = @_;
	$deviceInfos->{'SetFanSpeed'} = $temp;
	$deviceInfos->{'EffectiveFlags'} = "8";
	$deviceInfos->{'HasPendingCommand'} = "true";
	$json_device = JSON->new->utf8->encode($deviceInfos);
	#Variables
	my $url = 'https://app.melcloud.com/Mitsubishi.Wifi.Client/Device/SetAta';
	# set up the stuff 
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	require HTTP::Request;
	$req = HTTP::Request->new(POST => $url);
	$req->header("X-MitsContextKey" => $contextKey);
	$req->header('content-type' => 'application/json');
	$req->content($json_device);
	# Fire the cannon now ! 
	my $res = $ua->request($req);																						
	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;
	if (/Illegal Operation/ig || $err != 200) {
		print "Server returned error: $err\n";
	}
	else {
		my $decoded = JSON->new->utf8(0)->decode($_);
		#Send next update time to domoticz
		setDomDeviceNextUpdate($idx,$decoded);
		#######################
		# Futur fonction time
		#######################
		@time = split(/T/,$decoded->{'NextCommunication'});
		debug("Update device : ".time_offset($time[1],2) );
		return $result;
	}
}

sub setMELDeviceMode {
	#Parameters
	my ($contextKey,$mode,$deviceInfos,$idx) = @_;
	# Mode value : 1 warm, 2 dry, 3 cool, 7 vent, 8 auto
	if ($mode =~ warm) {
		$deviceInfos->{'OperationMode'} = 1;
	}
	elsif ($mode =~ dry) {
		$deviceInfos->{'OperationMode'} = 2;
	}
	elsif ($mode =~ cool) {
		$deviceInfos->{'OperationMode'} = 3;
	}
	elsif ($mode =~ vent) {
		$deviceInfos->{'OperationMode'} = 7;
	}
	elsif ($mode =~ auto) {
		$deviceInfos->{'OperationMode'} = 8;
	}	
	$deviceInfos->{'EffectiveFlags'} = "6";
	$deviceInfos->{'HasPendingCommand'} = "true";
	$json_device = JSON->new->utf8->encode($deviceInfos);
	#Variables
	my $url = 'https://app.melcloud.com/Mitsubishi.Wifi.Client/Device/SetAta';
	# set up the stuff 
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	require HTTP::Request;
	$req = HTTP::Request->new(POST => $url);
	$req->header("X-MitsContextKey" => $contextKey);
	$req->header('content-type' => 'application/json');
	$req->content($json_device);
	# Fire the cannon now ! 
	my $res = $ua->request($req);																						
	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;
	if (/Illegal Operation/ig || $err != 200) {
		print "Server returned error: $err\n";
	}
	else {
		my $decoded = JSON->new->utf8(0)->decode($_);
		#Send next update time to domoticz
		setDomDeviceNextUpdate($idx,$decoded);
		#######################
		# Futur fonction time
		#######################
		@time = split(/T/,$decoded->{'NextCommunication'});
		debug("Update device : ".time_offset($time[1],2) );
		return $result;
	}
}

sub setMELDeviceVane {
	#Parameters
	my ($contextKey,$vane,$deviceInfos,$idx) = @_;
	$deviceInfos->{'VaneVertical'} = $vane;
	$deviceInfos->{'EffectiveFlags'} = "16";
	$deviceInfos->{'HasPendingCommand'} = "true";
	$json_device = JSON->new->utf8->encode($deviceInfos);
	#Variables
	my $url = 'https://app.melcloud.com/Mitsubishi.Wifi.Client/Device/SetAta';
	# set up the stuff 
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	require HTTP::Request;
	$req = HTTP::Request->new(POST => $url);
	$req->header("X-MitsContextKey" => $contextKey);
	$req->header('content-type' => 'application/json');
	$req->content($json_device);
	# Fire the cannon now ! 
	my $res = $ua->request($req);																						
	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;
	if (/Illegal Operation/ig || $err != 200) {
		print "Server returned error: $err\n";
	}
	else {
		my $decoded = JSON->new->utf8(0)->decode($_);
		#Send next update time to domoticz
		setDomDeviceNextUpdate($idx,$decoded);
		#######################
		# Futur fonction time
		#######################
		@time = split(/T/,$decoded->{'NextCommunication'});
		debug("Update device : ".time_offset($time[1],2) );
		return $result;
	}
}

sub setMELDeviceTemp {
	#Parameters
	my ($contextKey,$temp,$deviceInfos,$idx) = @_;
	$deviceInfos->{'SetTemperature'} = $temp;
	$deviceInfos->{'EffectiveFlags'} = "4";
	$deviceInfos->{'HasPendingCommand'} = "true";
	$json_device = JSON->new->utf8->encode($deviceInfos);
	#Variables
	my $url = 'https://app.melcloud.com/Mitsubishi.Wifi.Client/Device/SetAta';
	# set up the stuff 
	my $ua = LWP::UserAgent->new();
	# Set our own user-agent string! 
	$ua->agent("Domoticz Gysmo");
	require HTTP::Request;
	$req = HTTP::Request->new(POST => $url);
	$req->header("X-MitsContextKey" => $contextKey);
	$req->header('content-type' => 'application/json');
	$req->content($json_device);
	# Fire the cannon now ! 
	my $res = $ua->request($req);																						
	# Get the error back from the server if any 
	my $err = $res->status_line; 
	# Get server body text, $_ used in regexp on next line 
	$_ = $res->decoded_content;
	if (/Illegal Operation/ig || $err != 200) {
		print "Server returned error: $err\n";
	}
	else {
		my $decoded = JSON->new->utf8(0)->decode($_);
		#Send next update time to domoticz
		setDomDeviceNextUpdate($idx,$decoded);
		#######################
		# Futur fonction time
		#######################
		@time = split(/T/,$decoded->{'NextCommunication'});
		debug("Update device : ".time_offset($time[1],2) );
		return $result;
	}
}

sub init_mel {
	#Parameters
	my ($search_name) = @_;
	$contextID = login($Email,$Password);
	foreach my $name (keys %devicesInfos)  {
		if ( $name =~ $search_name ) {
			$buildingID = getMELBuildingID($contextID,$name);
			$deviceID = getMELDeviceID($contextID,$name);
		}
	}
}

#####################################################
# Main program
#####################################################


#####################################################
# Arguments
#####################################################
if ($ARGV[0] =~ /report/) {
	$contextID = login($Email,$Password);
	foreach my $name (keys %devicesInfos)  {
		$buildingID = getMELBuildingID($contextID,$name);
		$deviceID = getMELDeviceID($contextID,$name);
		debug("############################");
		debug("# Reporting device: " . $name ." #");
		debug("############################");
		$infosAirCon = getAirConInfos($contextID,$deviceID,$buildingID);
		setDomDeviceTempRoom($devicesInfos{$name}{"idx_temp"},$infosAirCon);
		setDomDeviceNextUpdate($devicesInfos{$name}{"idx_update"},$infosAirCon);
		setDomDeviceTempClim($devicesInfos{$name}{"idx_setTemp"},$infosAirCon);
		setDomDeviceStatus($devicesInfos{$name}{"idx_status"},$infosAirCon);
		setDomDeviceMode($devicesInfos{$name}{"idx_modeCool"},$devicesInfos{$name}{"idx_modeWarm"},$infosAirCon);
	}
}
elsif ($ARGV[0] =~ /test/) {
	init_mel($ARGV[1]);
	debug("Send command to building:" . $buildingID);
	debug("Send command to device:" . $deviceID);
	
}

elsif ($ARGV[0] =~ /temp/ && exists $devicesInfos{$ARGV[2]}{'idx_status'}) {
	init_mel($ARGV[2]);
	@temp = split(/:/,$ARGV[1]);
	$infosAirCon = getAirConInfos($contextID,$deviceID,$buildingID);
	setMELDeviceTemp($contextID,$temp[0],$infosAirCon,$devicesInfos{$ARGV[2]}{'idx_update'});
}
elsif ($ARGV[0] =~ /fan/ && exists $devicesInfos{$ARGV[2]}{'idx_status'}) {
	init_mel($ARGV[2]);
	debug("Send commande to device:" . $buildingID);
	$infosAirCon = getAirConInfos($contextID,$deviceID,$buildingID);
	setMELDeviceFan($contextID,$ARGV[1],$infosAirCon,$devicesInfos{$ARGV[2]}{'idx_update'});
}
elsif ($ARGV[0] =~ /power/ && exists $devicesInfos{$ARGV[2]}{'idx_status'}) {
	init_mel($ARGV[2]);
	$infosAirCon = getAirConInfos($contextID,$deviceID,$buildingID);
	setMELDevicePower($contextID,$ARGV[1],$infosAirCon,$devicesInfos{$ARGV[2]}{'idx_update'});
}
elsif ($ARGV[0] =~ /mode/ && exists $devicesInfos{$ARGV[2]}{'idx_status'}) {
	init_mel($ARGV[2]);
	$infosAirCon = getAirConInfos($contextID,$deviceID,$buildingID);
	setMELDeviceMode($contextID,$ARGV[1],$infosAirCon,$devicesInfos{$ARGV[2]}{'idx_update'});
}
elsif ($ARGV[0] =~ /vane/ && exists $devicesInfos{$ARGV[2]}{'idx_status'}) {
	init_mel($ARGV[2]);
	$infosAirCon = getAirConInfos($contextID,$deviceID,$buildingID);
	setMELDeviceVane($contextID,$ARGV[1],$infosAirCon,$devicesInfos{$ARGV[2]}{'idx_update'});
}
elsif ($ARGV[0] =~ /help/) {
	print "report: send status of devices to domoticz. Use it for crontab\n";
	print "power on/off DEVICENAME: power on or off a device.\n";
	print "mode modename DEVICENAME: choose mode warm,dry,cool,vent or auto\n";
	print "temp T° DEVICENAME: set temperature device. \n";
	print "fan FAN_SPEED DEVICENAME: set fan speed of the device. \n";
	print "vane VANE_POS DEVICENAME: set van position to 1 - 5, 0 to auto and 7 to move . \n";
	print "more to come...\n";
}
else {
	print "Nothing to do. Type help for help ;)\n";
}

Re: [Perl] Control Mitsubishi MAC-557IF-E airconditioning

Posted: Monday 04 January 2016 0:42
by mikael
Hello,

I just tried your latest version, but it failed with the following error message :
'"' expected, at character offset 4 (before "Success: false, Erro...") at melcloud.pl line 295.
Before submitting, I took a quick look and found it's because my unit was not linked to an "area", as I had not devided my building into areas.
Changed that in order to get the script working. That will be good for me, so this is just a pointer for others if the issue arises.

Thanks for your work :)

Mikael

Re: [Perl] Control Mitsubishi MAC-557IF-E airconditioning

Posted: Tuesday 05 January 2016 19:40
by bran2000
Hi,
i try to add some arguments, not working

pi@DomoticzSam ~/domoticz/scripts $ perl mitsu.pl power on Cuisine
Nothing to do. Type help for help ;

i just try to execute your script with a ssh console, it miss something.

Re: [Perl] Control Mitsubishi MAC-557IF-E airconditioning

Posted: Wednesday 06 January 2016 19:14
by Sappien
I've just tried your script, but got also a error

'"' expected, at character offset 4 (before "Success: false, Erro...") at ./melcloud.pl line 175.

Re: [Perl] Control Mitsubishi MAC-557IF-E airconditioning

Posted: Wednesday 06 January 2016 20:23
by bran2000
Someone has the same error when you execute the script ?
pi@DomoticzSam ~/domoticz/scripts $ perl mitsu.pl power on Cuisine
Nothing to do. Type help for help ;

Re: [Perl] Control Mitsubishi MAC-557IF-E airconditioning

Posted: Wednesday 06 January 2016 21:52
by Sappien
I think that my Melcloud interface is different (because I've got a Ecodan)

Re: [Perl] Control Mitsubishi MAC-557IF-E airconditioning

Posted: Friday 08 January 2016 21:45
by Sappien
After some digging I think the problem has something to do with JSON and utf8 combination..

my $decoded = JSON->new->utf8(0)->decode($_);


root@debian:/var/bin/melcloud# ./melcloud.pl report
context ID: D11EB8E17DB94DD0BC8AE185035236
############################
# Reporting device: NAME_ON_MELCLOUD #
############################
'"' expected, at character offset 4 (before "Success: false, Erro...") at ./melcloud.pl line 294.

When I disable the JSON part and enable the debug option I'm getting the data from Melcloud

"SetTankWaterTemperature":44.0,"SetTemperatureZone1":22.0,"SetTemperatureZone2":20.0,"ForcedHotWaterMode":false,

When I enable the perl warning option I see some other issues.. There is a comparison check on the http status, but the value is "200 OK" instead of "200"

Argument "200 OK" isn't numeric in numeric ne (!=) at ./melcloud.pl line 194.

After changing the comparison I get the following error :roll:

malformed JSON string, neither array, object, number, string or atom, at character offset 4 (before "<!DOCTYPE html>\r\n\r...") at ./melcloud.pl line 300.

Re: [Perl] Control Mitsubishi MAC-557IF-E airconditioning

Posted: Saturday 16 January 2016 19:37
by Sappien
The control parts of the Ecodan serie is different than a air/air airconditioning :|

So I'm building a script special for the Ecodan..

Image

Re: [Perl] Control Mitsubishi MAC-557IF-E airconditioning

Posted: Friday 26 February 2016 23:40
by bagnico
Hi!
I modified the script to work without areas and some corrections (setDomDeviceMode works now)
Mode is now 'text" not switch

Code: Select all

#!/usr/bin/perl
#Dependency: libwww-perl, libjson-perl
# Original script : gysmo38
# Modifications : bagnico

###################################################
# Release notes
###################################################
# Version 0.3:
# - setDomDeviceMode OK
# - Script works with no Areas 
# - add 1 hours for uptime (for french)
# Version 0.2:
# - add 2 hours for uptime time (for french)
# - add mode option
# - add fan option
# - add vane option (only vertical)
# - add settemp option
# Version 0.1: First release (with very dirty code...)
# - switch on / off unit
# - report room temperature
# - report unit temperature set
# - report next unit update

use HTTP::Request::Common qw(POST GET);
use HTTP::Headers;
use LWP::UserAgent;
use JSON;     
use Data::Dumper;

#####################################################
# Configuration
#####################################################

my $Email = "mail\@mail.com";  # Email used to login to MELcloud
my $Password = "password";       # Password used lo login to MELcloud
my $debug = 0;                  # 0 = no debug, 1 = debug

my $domIP = "192.168.0.251";         # Domoticz IP 
my $domPORT = "8080";      # Domoticz PORT

my @devicesInfos;               # List of all devices. Add block for new devices
#Device 1
$devicesInfos{"SALON"}{"idx_status"} = "657";   # IDX of status device (type switch)
$devicesInfos{"SALON"}{"idx_temp"} = "658";      # IDX of temperature device (type temp)
$devicesInfos{"SALON"}{"idx_update"} = "659";   # IDX of update time device (type text)
$devicesInfos{"SALON"}{"idx_setTemp"} = "660";   # IDX of set temp device (type set point)
$devicesInfos{"SALON"}{"idx_mode"} = "666"; # IDX of mode (type text)

#Device n
# $devicesInfos{"Parents"}{"idx_status"} = "101";
# $devicesInfos{"Parents"}{"idx_temp"} = "94";
# $devicesInfos{"Parents"}{"idx_update"} = "109";
# $devicesInfos{"Parents"}{"idx_setTemp"} = "105";
# $devicesInfos{"Parents"}{"idx_mode"} = "666";


##########################################################
#   Functions
##########################################################

sub debug {
      my ($msg) = @_;
      if ($debug) {
         print $msg."\n";
      }
}

sub time_offset {
      my ($time,$offset) = @_;
      @split_time = split(/:/,$time);
	  # debug("Time: ".$split_time[0]);
      if ($split_time[0] <= 22) {
            $split_time[0] = $split_time[0] + 1;
      }
      elsif ($split_time[0] == 23) {
            $split_time[0] = 00;
      }
	  # debug("Time2: ".$split_time[0],$split_time[1],$split_time[2]);
      return join(":",$split_time[0],$split_time[1],$split_time[2]);
}

sub getDOMDeviceStatus {
      my ($idx) = @_;
      my $url = "http://$domIP:$domPORT/json.htm?type=devices&rid=".$idx;
      my $ua = LWP::UserAgent->new();
      # Set our own user-agent string! 
      $ua->agent("Domoticz Gysmo");
      require HTTP::Request;
      $req = HTTP::Request->new(GET => $url);
      # Fire the cannon now ! 
      my $res = $ua->request($req);                                                                  
      # Get the error back from the server if any 
      my $err = $res->status_line; 
      # Get server body text, $_ used in regexp on next line 
      $_ = $res->decoded_content;

      if (/Illegal Operation/ig || $err != 200) {
         return "Server returned error: $err\n";
      }
      else {
         $result = $1 if /(?:Status\"\ :)+(.*?),/s;
         debug("receive from domoticz: ".$result);
         return $result;
      }   
}

sub login {
   #Parameters
   my ($Email,$Password) = @_;
   #Variables
   my $AppVersion = "1.9.3.0";
   my $Language = "7";
   my $CaptchaChallenge = "";
   my $CaptchaResponse = "";
   my $Persist = "true";
   my $url = "https://app.melcloud.com/Mitsubishi.Wifi.Client/Login/ClientLogin";
   
   # set up the stuff 
   my $ua = LWP::UserAgent->new();
   # Set our own user-agent string! 
   $ua->agent("Domoticz Gysmo");

   # file.cgi should just return the data sent for this test 
   # These seem to be like <input type=text name=A value=$A > off a form... 
   my $req = POST $url, [
   AppVersion => "$AppVersion",
   CaptchaChallenge => "$CaptchaChallenge",
   CaptchaResponse => "$CaptchaResponse",
   Email => "$Email",
   Language => "$Language",
   Password => "$Password",
   Persist => "$Persist" 
   ];

   # Fire the cannon now ! 
   my $res = $ua->request($req);                                                                  

   # Get the error back from the server if any 
   my $err = $res->status_line; 
   # Get server body text, $_ used in regexp on next line 
   $_ = $res->decoded_content;

   if (/Illegal Operation/ig || $err != 200) {
      return "Server returned error: $err\n";
   }
   elsif(/\"ErrorId\":1/ig) {
      return "Bad password\n";
   }   
   elsif(/\"ErrorId\":null/ig) {
      $result  = $1 if /(?:ContextKey\":\")+(.*?)\"/s;
      debug ("context ID: ".$result);
      return $result;
   }
   else {
      return "Unknow error";
   }
}

sub getMELBuildingID {
   #Parameters
   my ($ContextKey,$devicename) = @_;
   #Variables
   my $url = "https://app.melcloud.com/Mitsubishi.Wifi.Client/User/ListDevices";
   # set up the stuff 
   my $ua = LWP::UserAgent->new();
   # Set our own user-agent string! 
   $ua->agent("Domoticz Gysmo");
   require HTTP::Request;
   $req = HTTP::Request->new(GET => $url);
   $req->header("X-MitsContextKey" => $ContextKey);
   # Fire the cannon now ! 
   my $res = $ua->request($req);                                                                  
   # Get the error back from the server if any 
   my $err = $res->status_line; 
   # Get server body text, $_ used in regexp on next line 
   $_ = $res->decoded_content;
   my $decoded = JSON->new->utf8(0)->decode($_);
   my $result = "0";
   foreach my $building (@$decoded) {
            @devices = @{$building->{'Structure'}{'Devices'}};
            foreach my $device (@devices) {
               if ( $device->{'DeviceName'} =~ $devicename) {
                  
                  $result =  $device->{'BuildingID'};
               }
            }
	  # debug("BuildingID: ".Dumper($result));
   }
   if (/Illegal Operation/ig || $err != 200) {
      return "Server returned error: $err\n";
   }
   else {
   # debug("Building ID: ".Dumper($decoded));
      return "$result";
   }
}

sub getMELDeviceID {
   #Parameters
   my ($ContextKey,$devicename) = @_;
   #Variables
   my $url = "https://app.melcloud.com/Mitsubishi.Wifi.Client/User/ListDevices";
   # set up the stuff 
   my $ua = LWP::UserAgent->new();
   # Set our own user-agent string! 
   $ua->agent("Domoticz Gysmo");
   
   require HTTP::Request;
   $req = HTTP::Request->new(GET => $url);
   $req->header("X-MitsContextKey" => $ContextKey);
   # Fire the cannon now ! 
   my $res = $ua->request($req);                                                                  

   # Get the error back from the server if any 
   my $err = $res->status_line; 
   # Get server body text, $_ used in regexp on next line 
   $_ = $res->decoded_content;
   my $decoded = JSON->new->utf8(0)->decode($_);
   my $result = "0";
   foreach my $building (@$decoded) {
            @devices = @{$building->{'Structure'}{'Devices'}};
            foreach my $device (@devices) {
               if ( $device->{'DeviceName'} =~ $devicename) {
                  
                  $result =  $device->{'DeviceID'};
               }
            }
	  # debug("DeviceID: ".Dumper($result));
   }
   if (/Illegal Operation/ig || $err != 200) {
      return "Server returned error: $err\n";
   }
   else {
      # debug("Device ID: ".Dumper($decoded));
      return "$result";
   }
}

sub listDevices {
   #Parameters
   my ($ContextKey) = @_;
   #Variables
   my $url = "https://app.melcloud.com/Mitsubishi.Wifi.Client/User/ListDevices";
   # set up the stuff 
   my $ua = LWP::UserAgent->new();
   # Set our own user-agent string! 
   $ua->agent("Domoticz Gysmo");
   
   require HTTP::Request;
   $req = HTTP::Request->new(GET => $url);
   $req->header("X-MitsContextKey" => $ContextKey);
   # Fire the cannon now ! 
   my $res = $ua->request($req);                                                                  

   # Get the error back from the server if any 
   my $err = $res->status_line; 
   # Get server body text, $_ used in regexp on next line 
   $_ = $res->decoded_content;

   if (/Illegal Operation/ig || $err != 200) {
      return "Server returned error: $err\n";
   }
   else {
      $result = $_;
      debug("list devices: ".$result);
      return "$result";
   }
}

sub getAirConInfos {
   #Parameters
   my ($contextKey,$deviceID,$buildingID) = @_;
   debug("getairconinfos : ".$contextKey,$deviceID,$buildingID);
   #Variables
   my $url = 'https://app.melcloud.com/Mitsubishi.Wifi.Client/Device/Get?id=' . $deviceID . '&buildingID=' . $buildingID;
   # debug("device status : ". $url);
   #return $url;
   # set up the stuff 
   my $ua = LWP::UserAgent->new();
   # Set our own user-agent string! 
   $ua->agent("Domoticz Gysmo");
   
   require HTTP::Request;
   
   $req = HTTP::Request->new(GET => $url);
   $req->header("X-MitsContextKey" => $contextKey);

   # Fire the cannon now ! 
   my $res = $ua->request($req);                                                                  

   # Get the error back from the server if any 
   my $err = $res->status_line; 
   # Get server body text, $_ used in regexp on next line 
   $json = $res->decoded_content;
   my $decoded = JSON->new->utf8(0)->decode($json);
    if (/Illegal Operation/ig || $err != 200) {
      return "Server returned error: $err\n";
   }
   else {
      # debug("device status : ". $decoded);
      return $decoded;
   }
}

sub setDomDeviceStatus {
   #Parameters
   my ($idDomDevice,$deviceInfos) = @_;
   #Variables
   $domStatus = getDOMDeviceStatus($idDomDevice);
   if ($deviceInfos->{'Power'} =~ /true/ && $domStatus =~ /"Off"/) {
      $switchcmd = "On";
   my $url = "http://$domIP:$domPORT/json.htm?type=command&param=switchlight&idx=".$idDomDevice."&switchcmd=".$switchcmd;
   debug("send to domoticz: ".$url);
   my $ua = LWP::UserAgent->new();
   # Set our own user-agent string! 
   $ua->agent("Domoticz Gysmo");
   
   require HTTP::Request;
   
   $req = HTTP::Request->new(GET => $url);
      # Fire the cannon now ! 
   my $res = $ua->request($req);                                                                  

   # Get the error back from the server if any 
   my $err = $res->status_line; 
   # Get server body text, $_ used in regexp on next line 
   $_ = $res->decoded_content;

   if (/Illegal Operation/ig || $err != 200) {
      return "Server returned error: $err\n";
   }
   else {
      $result = $1 if /(?:status\"\ :)+(.*?),/s;
      debug("receive from domoticz: ".$result);
      return $result;
   }
   }
   elsif ($deviceInfos->{'Power'} =~ /false/ && $domStatus =~ /"On"/) {
      $switchcmd = "Off";
      my $url = "http://$domIP:$domPORT/json.htm?type=command&param=switchlight&idx=".$idDomDevice."&switchcmd=".$switchcmd;
      debug("send to domoticz: ".$url);
      my $ua = LWP::UserAgent->new();
      # Set our own user-agent string! 
      $ua->agent("Domoticz Gysmo");
   
   require HTTP::Request;
   
   $req = HTTP::Request->new(GET => $url);
      # Fire the cannon now ! 
   my $res = $ua->request($req);                                                                  

   # Get the error back from the server if any 
   my $err = $res->status_line; 
   # Get server body text, $_ used in regexp on next line 
   $_ = $res->decoded_content;

   if (/Illegal Operation/ig || $err != 200) {
      return "Server returned error: $err\n";
   }
   else {
      $result = $1 if /(?:status\"\ :)+(.*?),/s;
      debug("receive from domoticz: ".$result);
      return $result;
   }
   }
   else {
         debug("send to domoticz: nothing to send");
   }
   
}

sub setDomDeviceTempRoom {
   #Parameters
   my ($idDomDevice,$deviceInfos) = @_;
   my $url = "http://$domIP:$domPORT/json.htm?type=command&param=udevice&idx=".$idDomDevice."&nvalue=0&svalue=".$deviceInfos->{'RoomTemperature'};
   debug("send to domoticz: ".$url);
   my $ua = LWP::UserAgent->new();
   # Set our own user-agent string! 
   $ua->agent("Domoticz Gysmo");
   require HTTP::Request;
   $req = HTTP::Request->new(GET => $url);
   # Fire the cannon now ! 
   my $res = $ua->request($req);                                                                  
   # Get the error back from the server if any 
   my $err = $res->status_line; 
   # Get server body text, $_ used in regexp on next line 
   $_ = $res->decoded_content;
   if (/Illegal Operation/ig || $err != 200) {
      return "Server returned error: $err\n";
   }
   else {
      $result = $1 if /(?:status\"\ :)+(.*?),/s;
      debug("receive from domoticz: ".$result);
      return $result;
   }
}

sub setDomDeviceNextUpdate {
   #Parameters
   my ($idDomDevice,$deviceInfos) = @_;
   @time = split(/T/,$deviceInfos->{'NextCommunication'});
   my $url = "http://$domIP:$domPORT/json.htm?type=command&param=udevice&idx=".$idDomDevice."&nvalue=0&svalue=".time_offset($time[1],2);
   debug("send to domoticz: ".$url);
   my $ua = LWP::UserAgent->new();
   # Set our own user-agent string! 
   $ua->agent("Domoticz Gysmo");
   
   require HTTP::Request;
   
   $req = HTTP::Request->new(GET => $url);
      # Fire the cannon now ! 
   my $res = $ua->request($req);                                                                  

   # Get the error back from the server if any 
   my $err = $res->status_line; 
   # Get server body text, $_ used in regexp on next line 
   $_ = $res->decoded_content;

   if (/Illegal Operation/ig || $err != 200) {
      return "Server returned error: $err\n";
   }
   else {
      $result = $1 if /(?:status\"\ :)+(.*?),/s;
      debug("receive from domoticz: ".$result);
      return $result;
   }
}


sub setDomDeviceTempClim {
   #Parameters
   my ($idDomDevice,$deviceInfos) = @_;
   my $url = "http://$domIP:$domPORT/json.htm?type=command&param=udevice&idx=".$idDomDevice."&nvalue=0&svalue=".$deviceInfos->{'SetTemperature'};
   debug("send to domoticz: ".$url);
   my $ua = LWP::UserAgent->new();
   # Set our own user-agent string! 
   $ua->agent("Domoticz Gysmo");
   
   require HTTP::Request;
   
   $req = HTTP::Request->new(GET => $url);
      # Fire the cannon now ! 
   my $res = $ua->request($req);                                                                  

   # Get the error back from the server if any 
   my $err = $res->status_line; 
   # Get server body text, $_ used in regexp on next line 
   $_ = $res->decoded_content;

   if (/Illegal Operation/ig || $err != 200) {
      return "Server returned error: $err\n";
   }
   else {
      $result = $1 if /(?:status\"\ :)+(.*?),/s;
      debug("receive from domoticz: ".$result);
      return $result;
   }
}

sub setDomDeviceMode {
   #Parameters
   my ($idDomDevice,$deviceInfos) = @_;
   my $mode = $deviceInfos->{'OperationMode'};
   if ( $mode == 1) {
      $modeclim = 'WARM';
	}
   elsif ( $mode == 2) {
      print "MODE DRY";
      $modeclim = 'DRY';
	}
   elsif ( $mode == 3) {
      $modeclim = 'COOL';
	}
   elsif ( $mode == 7) {
      $modeclim = 'VENT';
	}
   elsif ( $mode == 8) {
      $modeclim = 'AUTO';
	}
   my $url = "http://$domIP:$domPORT/json.htm?type=command&param=udevice&idx=".$idDomDevice."&nvalue=0&svalue=".$modeclim;
   debug("send to domoticz: ".$url);
   my $ua = LWP::UserAgent->new();
   # Set our own user-agent string! 
   $ua->agent("Domoticz Gysmo");
   require HTTP::Request;
   $req = HTTP::Request->new(GET => $url);
   # Fire the cannon now ! 
   my $res = $ua->request($req);                                                                  
   # Get the error back from the server if any 
   my $err = $res->status_line; 
   # Get server body text, $_ used in regexp on next line 
   $_ = $res->decoded_content;
   if (/Illegal Operation/ig || $err != 200) {
      return "Server returned error: $err\n";
   }
   else {
      $result = $1 if /(?:status\"\ :)+(.*?),/s;
      debug("receive from domoticz: ".$result);
      return $result;
   }
}

sub setMELDevicePower {
   #Parameters
   my ($contextKey,$status,$deviceInfos,$idx) = @_;
   if($status =~ /on/ ) {
      $deviceInfos->{'Power'} = "true";
   }
   elsif($status =~ /off/ ) {
      $deviceInfos->{'Power'} = "false";
   }
   $deviceInfos->{'EffectiveFlags'} = "1";
   $deviceInfos->{'HasPendingCommand'} = "true";
   $json_device = JSON->new->utf8->encode($deviceInfos);
   #Variables
   my $url = 'https://app.melcloud.com/Mitsubishi.Wifi.Client/Device/SetAta';
   #return $url;
   # set up the stuff 
   my $ua = LWP::UserAgent->new();
   # Set our own user-agent string! 
   $ua->agent("Domoticz Gysmo");
   
   require HTTP::Request;
   $req = HTTP::Request->new(POST => $url);
   $req->header("X-MitsContextKey" => $contextKey);
   $req->header('content-type' => 'application/json');
   $req->content($json_device);
   # Fire the cannon now ! 
   my $res = $ua->request($req);                                                                  

   # Get the error back from the server if any 
   my $err = $res->status_line; 
   # Get server body text, $_ used in regexp on next line 
   $_ = $res->decoded_content;
   debug($_);
   if (/Illegal Operation/ig || $err != 200) {
      print "Server returned error: $err\n";
   }
   else {
      my $decoded = JSON->new->utf8(0)->decode($_);
      #Send next update time to domoticz
      setDomDeviceNextUpdate($idx,$decoded);
      @time = split(/T/,$decoded->{'NextCommunication'});
      debug("Update device : ".time_offset($time[1],2) );
      return $result;
   }
}

sub setMELDeviceFan {
   #Parameters
   my ($contextKey,$temp,$deviceInfos,$idx) = @_;
   $deviceInfos->{'SetFanSpeed'} = $temp;
   $deviceInfos->{'EffectiveFlags'} = "8";
   $deviceInfos->{'HasPendingCommand'} = "true";
   $json_device = JSON->new->utf8->encode($deviceInfos);
   #Variables
   my $url = 'https://app.melcloud.com/Mitsubishi.Wifi.Client/Device/SetAta';
   # set up the stuff 
   my $ua = LWP::UserAgent->new();
   # Set our own user-agent string! 
   $ua->agent("Domoticz Gysmo");
   require HTTP::Request;
   $req = HTTP::Request->new(POST => $url);
   $req->header("X-MitsContextKey" => $contextKey);
   $req->header('content-type' => 'application/json');
   $req->content($json_device);
   # Fire the cannon now ! 
   my $res = $ua->request($req);                                                                  
   # Get the error back from the server if any 
   my $err = $res->status_line; 
   # Get server body text, $_ used in regexp on next line 
   $_ = $res->decoded_content;
   if (/Illegal Operation/ig || $err != 200) {
      print "Server returned error: $err\n";
   }
   else {
      my $decoded = JSON->new->utf8(0)->decode($_);
      #Send next update time to domoticz
      setDomDeviceNextUpdate($idx,$decoded);
      #######################
      # Futur fonction time
      #######################
      @time = split(/T/,$decoded->{'NextCommunication'});
      debug("Update device : ".time_offset($time[1],2) );
      return $result;
   }
}

sub setMELDeviceMode {
   #Parameters
   my ($contextKey,$mode,$deviceInfos,$idx) = @_;
   # Mode value : 1 warm, 2 dry, 3 cool, 7 vent, 8 auto
   if ($mode =~ warm) {
      $deviceInfos->{'OperationMode'} = 1;
   }
   elsif ($mode =~ dry) {
      $deviceInfos->{'OperationMode'} = 2;
   }
   elsif ($mode =~ cool) {
      $deviceInfos->{'OperationMode'} = 3;
   }
   elsif ($mode =~ vent) {
      $deviceInfos->{'OperationMode'} = 7;
   }
   elsif ($mode =~ auto) {
      $deviceInfos->{'OperationMode'} = 8;
   }   
   $deviceInfos->{'EffectiveFlags'} = "6";
   $deviceInfos->{'HasPendingCommand'} = "true";
   $json_device = JSON->new->utf8->encode($deviceInfos);
   #Variables
   my $url = 'https://app.melcloud.com/Mitsubishi.Wifi.Client/Device/SetAta';
   # set up the stuff 
   my $ua = LWP::UserAgent->new();
   # Set our own user-agent string! 
   $ua->agent("Domoticz Gysmo");
   require HTTP::Request;
   $req = HTTP::Request->new(POST => $url);
   $req->header("X-MitsContextKey" => $contextKey);
   $req->header('content-type' => 'application/json');
   $req->content($json_device);
   # Fire the cannon now ! 
   my $res = $ua->request($req);                                                                  
   # Get the error back from the server if any 
   my $err = $res->status_line; 
   # Get server body text, $_ used in regexp on next line 
   $_ = $res->decoded_content;
   if (/Illegal Operation/ig || $err != 200) {
      print "Server returned error: $err\n";
   }
   else {
      my $decoded = JSON->new->utf8(0)->decode($_);
      #Send next update time to domoticz
      setDomDeviceNextUpdate($idx,$decoded);
      #######################
      # Futur fonction time
      #######################
      @time = split(/T/,$decoded->{'NextCommunication'});
      debug("Update device : ".time_offset($time[1],2) );
      return $result;
   }
}

sub setMELDeviceVane {
   #Parameters
   my ($contextKey,$vane,$deviceInfos,$idx) = @_;
   $deviceInfos->{'VaneVertical'} = $vane;
   $deviceInfos->{'EffectiveFlags'} = "16";
   $deviceInfos->{'HasPendingCommand'} = "true";
   $json_device = JSON->new->utf8->encode($deviceInfos);
   #Variables
   my $url = 'https://app.melcloud.com/Mitsubishi.Wifi.Client/Device/SetAta';
   # set up the stuff 
   my $ua = LWP::UserAgent->new();
   # Set our own user-agent string! 
   $ua->agent("Domoticz Gysmo");
   require HTTP::Request;
   $req = HTTP::Request->new(POST => $url);
   $req->header("X-MitsContextKey" => $contextKey);
   $req->header('content-type' => 'application/json');
   $req->content($json_device);
   # Fire the cannon now ! 
   my $res = $ua->request($req);                                                                  
   # Get the error back from the server if any 
   my $err = $res->status_line; 
   # Get server body text, $_ used in regexp on next line 
   $_ = $res->decoded_content;
   if (/Illegal Operation/ig || $err != 200) {
      print "Server returned error: $err\n";
   }
   else {
      my $decoded = JSON->new->utf8(0)->decode($_);
      #Send next update time to domoticz
      setDomDeviceNextUpdate($idx,$decoded);
      #######################
      # Futur fonction time
      #######################
      @time = split(/T/,$decoded->{'NextCommunication'});
      debug("Update device : ".time_offset($time[1],2) );
      return $result;
   }
}

sub setMELDeviceTemp {
   #Parameters
   my ($contextKey,$temp,$deviceInfos,$idx) = @_;
   $deviceInfos->{'SetTemperature'} = $temp;
   $deviceInfos->{'EffectiveFlags'} = "4";
   $deviceInfos->{'HasPendingCommand'} = "true";
   $json_device = JSON->new->utf8->encode($deviceInfos);
   #Variables
   my $url = 'https://app.melcloud.com/Mitsubishi.Wifi.Client/Device/SetAta';
   # set up the stuff 
   my $ua = LWP::UserAgent->new();
   # Set our own user-agent string! 
   $ua->agent("Domoticz Gysmo");
   require HTTP::Request;
   $req = HTTP::Request->new(POST => $url);
   $req->header("X-MitsContextKey" => $contextKey);
   $req->header('content-type' => 'application/json');
   $req->content($json_device);
   # Fire the cannon now ! 
   my $res = $ua->request($req);                                                                  
   # Get the error back from the server if any 
   my $err = $res->status_line; 
   # Get server body text, $_ used in regexp on next line 
   $_ = $res->decoded_content;
   if (/Illegal Operation/ig || $err != 200) {
      print "Server returned error: $err\n";
   }
   else {
      my $decoded = JSON->new->utf8(0)->decode($_);
      #Send next update time to domoticz
      setDomDeviceNextUpdate($idx,$decoded);
      #######################
      # Futur fonction time
      #######################
      @time = split(/T/,$decoded->{'NextCommunication'});
      debug("Update device : ".time_offset($time[1],2) );
      return $result;
   }
}

sub init_mel {
   #Parameters
   my ($search_name) = @_;
   $contextID = login($Email,$Password);
   foreach my $name (keys %devicesInfos)  {
      if ( $name =~ $search_name ) {
         $buildingID = getMELBuildingID($contextID,$name);
         $deviceID = getMELDeviceID($contextID,$name);
      }
   }
}

#####################################################
# Main program
#####################################################


#####################################################
# Arguments
#####################################################
if ($ARGV[0] =~ /report/) {
   $contextID = login($Email,$Password);
   foreach my $name (keys %devicesInfos)  {
      $buildingID = getMELBuildingID($contextID,$name);
      $deviceID = getMELDeviceID($contextID,$name);
      debug("############################");
      debug("# Reporting device: " . $name ." #");
      debug("############################");
      $infosAirCon = getAirConInfos($contextID,$deviceID,$buildingID);
      setDomDeviceTempRoom($devicesInfos{$name}{"idx_temp"},$infosAirCon);
      setDomDeviceNextUpdate($devicesInfos{$name}{"idx_update"},$infosAirCon);
      setDomDeviceTempClim($devicesInfos{$name}{"idx_setTemp"},$infosAirCon);
      setDomDeviceStatus($devicesInfos{$name}{"idx_status"},$infosAirCon);
      setDomDeviceMode($devicesInfos{$name}{"idx_mode"},$infosAirCon);
   }
}
elsif ($ARGV[0] =~ /test/) {
   init_mel($ARGV[1]);
   debug("Send command to building:" . $buildingID);
   debug("Send command to device:" . $deviceID);
   
}

elsif ($ARGV[0] =~ /temp/ && exists $devicesInfos{$ARGV[2]}{'idx_status'}) {
   init_mel($ARGV[2]);
   @temp = split(/:/,$ARGV[1]);
   $infosAirCon = getAirConInfos($contextID,$deviceID,$buildingID);
   setMELDeviceTemp($contextID,$temp[0],$infosAirCon,$devicesInfos{$ARGV[2]}{'idx_update'});
}
elsif ($ARGV[0] =~ /fan/ && exists $devicesInfos{$ARGV[2]}{'idx_status'}) {
   init_mel($ARGV[2]);
   debug("Send commande to device:" . $buildingID);
   $infosAirCon = getAirConInfos($contextID,$deviceID,$buildingID);
   setMELDeviceFan($contextID,$ARGV[1],$infosAirCon,$devicesInfos{$ARGV[2]}{'idx_update'});
}
elsif ($ARGV[0] =~ /power/ && exists $devicesInfos{$ARGV[2]}{'idx_status'}) {
   init_mel($ARGV[2]);
   $infosAirCon = getAirConInfos($contextID,$deviceID,$buildingID);
   setMELDevicePower($contextID,$ARGV[1],$infosAirCon,$devicesInfos{$ARGV[2]}{'idx_update'});
}
elsif ($ARGV[0] =~ /mode/ && exists $devicesInfos{$ARGV[2]}{'idx_status'}) {
   init_mel($ARGV[2]);
   $infosAirCon = getAirConInfos($contextID,$deviceID,$buildingID);
   setMELDeviceMode($contextID,$ARGV[1],$infosAirCon,$devicesInfos{$ARGV[2]}{'idx_update'});
}
elsif ($ARGV[0] =~ /vane/ && exists $devicesInfos{$ARGV[2]}{'idx_status'}) {
   init_mel($ARGV[2]);
   $infosAirCon = getAirConInfos($contextID,$deviceID,$buildingID);
   setMELDeviceVane($contextID,$ARGV[1],$infosAirCon,$devicesInfos{$ARGV[2]}{'idx_update'});
}
elsif ($ARGV[0] =~ /help/) {
   print "report: send status of devices to domoticz. Use it for crontab\n";
   print "power on/off DEVICENAME: power on or off a device.\n";
   print "mode modename DEVICENAME: choose mode warm,dry,cool,vent or auto\n";
   print "temp T° DEVICENAME: set temperature device. \n";
   print "fan FAN_SPEED DEVICENAME: set fan speed of the device. \n";
   print "vane VANE_POS DEVICENAME: set van position to 1 - 5, 0 to auto and 7 to move . \n";
   print "more to come...\n";
}
else {
   print "Nothing to do. Type help for help ;)\n";
}
Image

Image

Re: [Perl] Control Mitsubishi MAC-557IF-E airconditioning

Posted: Saturday 27 February 2016 18:39
by bagnico
Version 0.4

# - add vane option horizontal
# - Change report to domoticz for informations (MODE | T°C SET | TIME_NEXT_UPDATE)
# - Change split time (remove .xxx)

Code: Select all

#!/usr/bin/perl
#Dependency: libwww-perl, libjson-perl
# Original script : gysmo38
# Modifications : bagnico

###################################################
# Release notes
###################################################
# Version 0.4:
# - add vane option horizontal
# - Change report to domoticz for informations (MODE | T°C | TIME_NEXT_UPDATE) 
# - Change split time (remove .xxx)
# Version 0.3:
# - setDomDeviceMode OK
# - Script works with no Areas 
# - add 1 hours for uptime (for french)
# Version 0.2:
# - add 2 hours for uptime time (for french)
# - add mode option
# - add fan option
# - add vane option (only vertical)
# - add settemp option
# Version 0.1: First release (with very dirty code...)
# - switch on / off unit
# - report room temperature
# - report unit temperature set
# - report next unit update

use HTTP::Request::Common qw(POST GET);
use HTTP::Headers;
use LWP::UserAgent;
use JSON;     
use Data::Dumper;

#####################################################
# Configuration
#####################################################

my $Email = "mail\@mail.com";  # Email used to login to MELcloud
my $Password = "password";       # Password used lo login to MELcloud
my $debug = 1;                  # 0 = no debug, 1 = debug

my $domIP = "192.168.0.251";         # Domoticz IP 
my $domPORT = "8080";      # Domoticz PORT

my @devicesInfos;               # List of all devices. Add block for new devices
#Device 1
$devicesInfos{"SALON"}{"idx_status"} = "657";   # IDX of status device (type switch)
$devicesInfos{"SALON"}{"idx_temp"} = "658";      # IDX of temperature device (type temp)
$devicesInfos{"SALON"}{"idx_info"} = "666"; # IDX of mode (type text)

#Device n
# $devicesInfos{"CHAMBRE"}{"idx_status"} = "657";   # IDX of status device (type switch)
# $devicesInfos{"CHAMBRE"}{"idx_temp"} = "658";      # IDX of temperature device (type temp)
# $devicesInfos{"CHAMBRE"}{"idx_info"} = "666"; # IDX of mode (type text)


##########################################################
#   Functions
##########################################################

sub debug {
      my ($msg) = @_;
      if ($debug) {
         print $msg."\n";
      }
}

sub time_offset {
      my ($time,$offset) = @_;
      @split_time = split(/:/,$time);
	  # debug("Time: ".$split_time[0]);
      if ($split_time[0] <= 22) {
            $split_time[0] = $split_time[0] + 1;
      }
      elsif ($split_time[0] == 23) {
            $split_time[0] = 00;
      }
	  $result = join(":",$split_time[0],$split_time[1],$split_time[2]);
	  @timeok = split(/\./,$result);
      return $timeok[0];
}

sub getDOMDeviceStatus {
      my ($idx) = @_;
      my $url = "http://$domIP:$domPORT/json.htm?type=devices&rid=".$idx;
      my $ua = LWP::UserAgent->new();
      # Set our own user-agent string! 
      $ua->agent("Domoticz Gysmo");
      require HTTP::Request;
      $req = HTTP::Request->new(GET => $url);
      # Fire the cannon now ! 
      my $res = $ua->request($req);                                                                  
      # Get the error back from the server if any 
      my $err = $res->status_line; 
      # Get server body text, $_ used in regexp on next line 
      $_ = $res->decoded_content;

      if (/Illegal Operation/ig || $err != 200) {
         return "Server returned error: $err\n";
      }
      else {
         $result = $1 if /(?:Status\"\ :)+(.*?),/s;
         debug("receive from domoticz: ".$result);
         return $result;
      }   
}

sub login {
   #Parameters
   my ($Email,$Password) = @_;
   #Variables
   my $AppVersion = "1.9.3.0";
   my $Language = "7";
   my $CaptchaChallenge = "";
   my $CaptchaResponse = "";
   my $Persist = "true";
   my $url = "https://app.melcloud.com/Mitsubishi.Wifi.Client/Login/ClientLogin";
   
   # set up the stuff 
   my $ua = LWP::UserAgent->new();
   # Set our own user-agent string! 
   $ua->agent("Domoticz Gysmo");

   # file.cgi should just return the data sent for this test 
   # These seem to be like <input type=text name=A value=$A > off a form... 
   my $req = POST $url, [
   AppVersion => "$AppVersion",
   CaptchaChallenge => "$CaptchaChallenge",
   CaptchaResponse => "$CaptchaResponse",
   Email => "$Email",
   Language => "$Language",
   Password => "$Password",
   Persist => "$Persist" 
   ];

   # Fire the cannon now ! 
   my $res = $ua->request($req);                                                                  

   # Get the error back from the server if any 
   my $err = $res->status_line; 
   # Get server body text, $_ used in regexp on next line 
   $_ = $res->decoded_content;

   if (/Illegal Operation/ig || $err != 200) {
      return "Server returned error: $err\n";
   }
   elsif(/\"ErrorId\":1/ig) {
      return "Bad password\n";
   }   
   elsif(/\"ErrorId\":null/ig) {
      $result  = $1 if /(?:ContextKey\":\")+(.*?)\"/s;
      debug ("context ID: ".$result);
      return $result;
   }
   else {
      return "Unknow error";
   }
}

sub getMELBuildingID {
   #Parameters
   my ($ContextKey,$devicename) = @_;
   #Variables
   my $url = "https://app.melcloud.com/Mitsubishi.Wifi.Client/User/ListDevices";
   # set up the stuff 
   my $ua = LWP::UserAgent->new();
   # Set our own user-agent string! 
   $ua->agent("Domoticz Gysmo");
   require HTTP::Request;
   $req = HTTP::Request->new(GET => $url);
   $req->header("X-MitsContextKey" => $ContextKey);
   # Fire the cannon now ! 
   my $res = $ua->request($req);                                                                  
   # Get the error back from the server if any 
   my $err = $res->status_line; 
   # Get server body text, $_ used in regexp on next line 
   $_ = $res->decoded_content;
   my $decoded = JSON->new->utf8(0)->decode($_);
   my $result = "0";
   foreach my $building (@$decoded) {
            @devices = @{$building->{'Structure'}{'Devices'}};
            foreach my $device (@devices) {
               if ( $device->{'DeviceName'} =~ $devicename) {
                  
                  $result =  $device->{'BuildingID'};
               }
            }
	  # debug("BuildingID: ".Dumper($result));
   }
   if (/Illegal Operation/ig || $err != 200) {
      return "Server returned error: $err\n";
   }
   else {
   # debug("Building ID: ".Dumper($decoded));
      return "$result";
   }
}

sub getMELDeviceID {
   #Parameters
   my ($ContextKey,$devicename) = @_;
   #Variables
   my $url = "https://app.melcloud.com/Mitsubishi.Wifi.Client/User/ListDevices";
   # set up the stuff 
   my $ua = LWP::UserAgent->new();
   # Set our own user-agent string! 
   $ua->agent("Domoticz Gysmo");
   
   require HTTP::Request;
   $req = HTTP::Request->new(GET => $url);
   $req->header("X-MitsContextKey" => $ContextKey);
   # Fire the cannon now ! 
   my $res = $ua->request($req);                                                                  

   # Get the error back from the server if any 
   my $err = $res->status_line; 
   # Get server body text, $_ used in regexp on next line 
   $_ = $res->decoded_content;
   my $decoded = JSON->new->utf8(0)->decode($_);
   my $result = "0";
   foreach my $building (@$decoded) {
            @devices = @{$building->{'Structure'}{'Devices'}};
            foreach my $device (@devices) {
               if ( $device->{'DeviceName'} =~ $devicename) {
                  
                  $result =  $device->{'DeviceID'};
               }
            }
	  # debug("DeviceID: ".Dumper($result));
   }
   if (/Illegal Operation/ig || $err != 200) {
      return "Server returned error: $err\n";
   }
   else {
      # debug("Device ID: ".Dumper($decoded));
      return "$result";
   }
}

sub listDevices {
   #Parameters
   my ($ContextKey) = @_;
   #Variables
   my $url = "https://app.melcloud.com/Mitsubishi.Wifi.Client/User/ListDevices";
   # set up the stuff 
   my $ua = LWP::UserAgent->new();
   # Set our own user-agent string! 
   $ua->agent("Domoticz Gysmo");
   
   require HTTP::Request;
   $req = HTTP::Request->new(GET => $url);
   $req->header("X-MitsContextKey" => $ContextKey);
   # Fire the cannon now ! 
   my $res = $ua->request($req);                                                                  

   # Get the error back from the server if any 
   my $err = $res->status_line; 
   # Get server body text, $_ used in regexp on next line 
   $_ = $res->decoded_content;

   if (/Illegal Operation/ig || $err != 200) {
      return "Server returned error: $err\n";
   }
   else {
      $result = $_;
      debug("list devices: ".$result);
      return "$result";
   }
}

sub getAirConInfos {
   #Parameters
   my ($contextKey,$deviceID,$buildingID) = @_;
   debug("getairconinfos : ".$contextKey,$deviceID,$buildingID);
   #Variables
   my $url = 'https://app.melcloud.com/Mitsubishi.Wifi.Client/Device/Get?id=' . $deviceID . '&buildingID=' . $buildingID;
   # debug("device status : ". $url);
   #return $url;
   # set up the stuff 
   my $ua = LWP::UserAgent->new();
   # Set our own user-agent string! 
   $ua->agent("Domoticz Gysmo");
   
   require HTTP::Request;
   
   $req = HTTP::Request->new(GET => $url);
   $req->header("X-MitsContextKey" => $contextKey);

   # Fire the cannon now ! 
   my $res = $ua->request($req);                                                                  

   # Get the error back from the server if any 
   my $err = $res->status_line; 
   # Get server body text, $_ used in regexp on next line 
   $json = $res->decoded_content;
   my $decoded = JSON->new->utf8(0)->decode($json);
    if (/Illegal Operation/ig || $err != 200) {
      return "Server returned error: $err\n";
   }
   else {
      # debug("device status : ". $decoded);
      return $decoded;
   }
}

sub setDomDeviceStatus {
   #Parameters
   my ($idDomDevice,$deviceInfos) = @_;
   #Variables
   $domStatus = getDOMDeviceStatus($idDomDevice);
   if ($deviceInfos->{'Power'} =~ /true/ && $domStatus =~ /"Off"/) {
      $switchcmd = "On";
   my $url = "http://$domIP:$domPORT/json.htm?type=command&param=switchlight&idx=".$idDomDevice."&switchcmd=".$switchcmd;
   debug("send to domoticz: ".$url);
   my $ua = LWP::UserAgent->new();
   # Set our own user-agent string! 
   $ua->agent("Domoticz Gysmo");
   
   require HTTP::Request;
   
   $req = HTTP::Request->new(GET => $url);
      # Fire the cannon now ! 
   my $res = $ua->request($req);                                                                  

   # Get the error back from the server if any 
   my $err = $res->status_line; 
   # Get server body text, $_ used in regexp on next line 
   $_ = $res->decoded_content;

   if (/Illegal Operation/ig || $err != 200) {
      return "Server returned error: $err\n";
   }
   else {
      $result = $1 if /(?:status\"\ :)+(.*?),/s;
      debug("receive from domoticz: ".$result);
      return $result;
   }
   }
   elsif ($deviceInfos->{'Power'} =~ /false/ && $domStatus =~ /"On"/) {
      $switchcmd = "Off";
      my $url = "http://$domIP:$domPORT/json.htm?type=command&param=switchlight&idx=".$idDomDevice."&switchcmd=".$switchcmd;
      debug("send to domoticz: ".$url);
      my $ua = LWP::UserAgent->new();
      # Set our own user-agent string! 
      $ua->agent("Domoticz Gysmo");
   
   require HTTP::Request;
   
   $req = HTTP::Request->new(GET => $url);
      # Fire the cannon now ! 
   my $res = $ua->request($req);                                                                  

   # Get the error back from the server if any 
   my $err = $res->status_line; 
   # Get server body text, $_ used in regexp on next line 
   $_ = $res->decoded_content;

   if (/Illegal Operation/ig || $err != 200) {
      return "Server returned error: $err\n";
   }
   else {
      $result = $1 if /(?:status\"\ :)+(.*?),/s;
      debug("receive from domoticz: ".$result);
      return $result;
   }
   }
   else {
         debug("send to domoticz: nothing to send");
   }
   
}

sub setDomDeviceTempRoom {
   #Parameters
   my ($idDomDevice,$deviceInfos) = @_;
   my $url = "http://$domIP:$domPORT/json.htm?type=command&param=udevice&idx=".$idDomDevice."&nvalue=0&svalue=".$deviceInfos->{'RoomTemperature'};
   debug("send to domoticz: ".$url);
   my $ua = LWP::UserAgent->new();
   # Set our own user-agent string! 
   $ua->agent("Domoticz Gysmo");
   require HTTP::Request;
   $req = HTTP::Request->new(GET => $url);
   # Fire the cannon now ! 
   my $res = $ua->request($req);                                                                  
   # Get the error back from the server if any 
   my $err = $res->status_line; 
   # Get server body text, $_ used in regexp on next line 
   $_ = $res->decoded_content;
   if (/Illegal Operation/ig || $err != 200) {
      return "Server returned error: $err\n";
   }
   else {
      $result = $1 if /(?:status\"\ :)+(.*?),/s;
      debug("receive from domoticz: ".$result);
      return $result;
   }
}

sub setDomDeviceInfo {
   #Parameters
   my ($idDomDevice,$deviceInfos) = @_;
   my $mode = $deviceInfos->{'OperationMode'};
   @timenextupdate = split(/T/,$deviceInfos->{'NextCommunication'});
   if ( $mode == 1) {
      $modeclim = 'MODE CHAUD';
	}
   elsif ( $mode == 2) {
      $modeclim = 'MODE SECHAGE';
	}
   elsif ( $mode == 3) {
      $modeclim = 'MODE FROID';
	}
   elsif ( $mode == 7) {
      $modeclim = 'MODE VENTILATION';
	}
   elsif ( $mode == 8) {
      $modeclim = 'MODE AUTO';
	}
   my $url = "http://$domIP:$domPORT/json.htm?type=command&param=udevice&idx=".$idDomDevice."&nvalue=0&svalue=".$modeclim."%20|%20 ".$deviceInfos->{'SetTemperature'}."%20°C%20|%20".time_offset($timenextupdate[1],2);
   debug("send to domoticz: ".$url);
   my $ua = LWP::UserAgent->new();
   # Set our own user-agent string! 
   $ua->agent("Domoticz Gysmo");
   require HTTP::Request;
   $req = HTTP::Request->new(GET => $url);
   # Fire the cannon now ! 
   my $res = $ua->request($req);                                                                  
   # Get the error back from the server if any 
   my $err = $res->status_line; 
   # Get server body text, $_ used in regexp on next line 
   $_ = $res->decoded_content;
   if (/Illegal Operation/ig || $err != 200) {
      return "Server returned error: $err\n";
   }
   else {
      $result = $1 if /(?:status\"\ :)+(.*?),/s;
      debug("receive from domoticz: ".$result);
      return $result;
   }
}

sub setMELDevicePower {
   #Parameters
   my ($contextKey,$status,$deviceInfos,$idx) = @_;
   if($status =~ /on/ ) {
      $deviceInfos->{'Power'} = "true";
   }
   elsif($status =~ /off/ ) {
      $deviceInfos->{'Power'} = "false";
   }
   $deviceInfos->{'EffectiveFlags'} = "1";
   $deviceInfos->{'HasPendingCommand'} = "true";
   $json_device = JSON->new->utf8->encode($deviceInfos);
   #Variables
   my $url = 'https://app.melcloud.com/Mitsubishi.Wifi.Client/Device/SetAta';
   #return $url;
   # set up the stuff 
   my $ua = LWP::UserAgent->new();
   # Set our own user-agent string! 
   $ua->agent("Domoticz Gysmo");
   
   require HTTP::Request;
   $req = HTTP::Request->new(POST => $url);
   $req->header("X-MitsContextKey" => $contextKey);
   $req->header('content-type' => 'application/json');
   $req->content($json_device);
   # Fire the cannon now ! 
   my $res = $ua->request($req);                                                                  

   # Get the error back from the server if any 
   my $err = $res->status_line; 
   # Get server body text, $_ used in regexp on next line 
   $_ = $res->decoded_content;
   debug($_);
   if (/Illegal Operation/ig || $err != 200) {
      print "Server returned error: $err\n";
   }
   else {
      debug("Update setMELDevicePower : OK");
   }
}

sub setMELDeviceFan {
   #Parameters
   my ($contextKey,$temp,$deviceInfos,$idx) = @_;
   $deviceInfos->{'SetFanSpeed'} = $temp;
   $deviceInfos->{'EffectiveFlags'} = "8";
   $deviceInfos->{'HasPendingCommand'} = "true";
   $json_device = JSON->new->utf8->encode($deviceInfos);
   #Variables
   my $url = 'https://app.melcloud.com/Mitsubishi.Wifi.Client/Device/SetAta';
   # set up the stuff 
   my $ua = LWP::UserAgent->new();
   # Set our own user-agent string! 
   $ua->agent("Domoticz Gysmo");
   require HTTP::Request;
   $req = HTTP::Request->new(POST => $url);
   $req->header("X-MitsContextKey" => $contextKey);
   $req->header('content-type' => 'application/json');
   $req->content($json_device);
   # Fire the cannon now ! 
   my $res = $ua->request($req);                                                                  
   # Get the error back from the server if any 
   my $err = $res->status_line; 
   # Get server body text, $_ used in regexp on next line 
   $_ = $res->decoded_content;
   if (/Illegal Operation/ig || $err != 200) {
      print "Server returned error: $err\n";
   }
   else {
      debug("Update setMELDeviceFan : OK");
   }
}

sub setMELDeviceMode {
   #Parameters
   my ($contextKey,$mode,$deviceInfos,$idx) = @_;
   # Mode value : 1 warm, 2 dry, 3 cool, 7 vent, 8 auto
   if ($mode =~ warm) {
      $deviceInfos->{'OperationMode'} = 1;
   }
   elsif ($mode =~ dry) {
      $deviceInfos->{'OperationMode'} = 2;
   }
   elsif ($mode =~ cool) {
      $deviceInfos->{'OperationMode'} = 3;
   }
   elsif ($mode =~ vent) {
      $deviceInfos->{'OperationMode'} = 7;
   }
   elsif ($mode =~ auto) {
      $deviceInfos->{'OperationMode'} = 8;
   }   
   $deviceInfos->{'EffectiveFlags'} = "6";
   $deviceInfos->{'HasPendingCommand'} = "true";
   $json_device = JSON->new->utf8->encode($deviceInfos);
   #Variables
   my $url = 'https://app.melcloud.com/Mitsubishi.Wifi.Client/Device/SetAta';
   # set up the stuff 
   my $ua = LWP::UserAgent->new();
   # Set our own user-agent string! 
   $ua->agent("Domoticz Gysmo");
   require HTTP::Request;
   $req = HTTP::Request->new(POST => $url);
   $req->header("X-MitsContextKey" => $contextKey);
   $req->header('content-type' => 'application/json');
   $req->content($json_device);
   # Fire the cannon now ! 
   my $res = $ua->request($req);                                                                  
   # Get the error back from the server if any 
   my $err = $res->status_line; 
   # Get server body text, $_ used in regexp on next line 
   $_ = $res->decoded_content;
   if (/Illegal Operation/ig || $err != 200) {
      print "Server returned error: $err\n";
   }
   else {
      debug("Update setMELDeviceMode : OK");
   }
}

sub setMELDeviceVaneVertical {
   #Parameters
   my ($contextKey,$vane,$deviceInfos,$idx) = @_;
   $deviceInfos->{'VaneVertical'} = $vane;
   $deviceInfos->{'EffectiveFlags'} = "16";
   $deviceInfos->{'HasPendingCommand'} = "true";
   $json_device = JSON->new->utf8->encode($deviceInfos);
   #Variables
   my $url = 'https://app.melcloud.com/Mitsubishi.Wifi.Client/Device/SetAta';
   # set up the stuff 
   my $ua = LWP::UserAgent->new();
   # Set our own user-agent string! 
   $ua->agent("Domoticz Gysmo");
   require HTTP::Request;
   $req = HTTP::Request->new(POST => $url);
   $req->header("X-MitsContextKey" => $contextKey);
   $req->header('content-type' => 'application/json');
   $req->content($json_device);
   # Fire the cannon now ! 
   my $res = $ua->request($req);                                                                  
   # Get the error back from the server if any 
   my $err = $res->status_line; 
   # Get server body text, $_ used in regexp on next line 
   $_ = $res->decoded_content;
   if (/Illegal Operation/ig || $err != 200) {
      print "Server returned error: $err\n";
   }
   else {
      debug("Update setMELDeviceVaneVertical : OK");
   }
}

sub setMELDeviceVaneHorizontal {
   #Parameters
   my ($contextKey,$vane,$deviceInfos,$idx) = @_;
   $deviceInfos->{'VaneHorizontal'} = $vane;
   $deviceInfos->{'EffectiveFlags'} = "16";
   $deviceInfos->{'HasPendingCommand'} = "true";
   $json_device = JSON->new->utf8->encode($deviceInfos);
   #Variables
   my $url = 'https://app.melcloud.com/Mitsubishi.Wifi.Client/Device/SetAta';
   # set up the stuff 
   my $ua = LWP::UserAgent->new();
   # Set our own user-agent string! 
   $ua->agent("Domoticz Gysmo");
   require HTTP::Request;
   $req = HTTP::Request->new(POST => $url);
   $req->header("X-MitsContextKey" => $contextKey);
   $req->header('content-type' => 'application/json');
   $req->content($json_device);
   # Fire the cannon now ! 
   my $res = $ua->request($req);                                                                  
   # Get the error back from the server if any 
   my $err = $res->status_line; 
   # Get server body text, $_ used in regexp on next line 
   $_ = $res->decoded_content;
   if (/Illegal Operation/ig || $err != 200) {
      print "Server returned error: $err\n";
   }
   else {
      debug("Update setMELDeviceVaneHorizontal : OK");
   }
}

sub setMELDeviceTemp {
   #Parameters
   my ($contextKey,$temp,$deviceInfos,$idx) = @_;
   $deviceInfos->{'SetTemperature'} = $temp;
   $deviceInfos->{'EffectiveFlags'} = "4";
   $deviceInfos->{'HasPendingCommand'} = "true";
   $json_device = JSON->new->utf8->encode($deviceInfos);
   #Variables
   my $url = 'https://app.melcloud.com/Mitsubishi.Wifi.Client/Device/SetAta';
   # set up the stuff 
   my $ua = LWP::UserAgent->new();
   # Set our own user-agent string! 
   $ua->agent("Domoticz Gysmo");
   require HTTP::Request;
   $req = HTTP::Request->new(POST => $url);
   $req->header("X-MitsContextKey" => $contextKey);
   $req->header('content-type' => 'application/json');
   $req->content($json_device);
   # Fire the cannon now ! 
   my $res = $ua->request($req);                                                                  
   # Get the error back from the server if any 
   my $err = $res->status_line; 
   # Get server body text, $_ used in regexp on next line 
   $_ = $res->decoded_content;
   if (/Illegal Operation/ig || $err != 200) {
      print "Server returned error: $err\n";
   }
   else {
      debug("Update setMELDeviceTemp : OK");
   }
}

sub init_mel {
   #Parameters
   my ($search_name) = @_;
   $contextID = login($Email,$Password);
   foreach my $name (keys %devicesInfos)  {
      if ( $name =~ $search_name ) {
         $buildingID = getMELBuildingID($contextID,$name);
         $deviceID = getMELDeviceID($contextID,$name);
      }
   }
}

#####################################################
# Main program
#####################################################


#####################################################
# Arguments
#####################################################
if ($ARGV[0] =~ /report/) {
   $contextID = login($Email,$Password);
   foreach my $name (keys %devicesInfos)  {
      $buildingID = getMELBuildingID($contextID,$name);
      $deviceID = getMELDeviceID($contextID,$name);
      debug("############################");
      debug("# Reporting device: " . $name ." #");
      debug("############################");
      $infosAirCon = getAirConInfos($contextID,$deviceID,$buildingID);
      setDomDeviceTempRoom($devicesInfos{$name}{"idx_temp"},$infosAirCon);
      setDomDeviceStatus($devicesInfos{$name}{"idx_status"},$infosAirCon);
      setDomDeviceInfo($devicesInfos{$name}{"idx_info"},$infosAirCon);
   }
}
elsif ($ARGV[0] =~ /test/) {
   init_mel($ARGV[1]);
   debug("Send command to building:" . $buildingID);
   debug("Send command to device:" . $deviceID);
   
}

elsif ($ARGV[0] =~ /temp/ && exists $devicesInfos{$ARGV[2]}{'idx_status'}) {
   init_mel($ARGV[2]);
   @temp = split(/:/,$ARGV[1]);
   $infosAirCon = getAirConInfos($contextID,$deviceID,$buildingID);
   setMELDeviceTemp($contextID,$temp[0],$infosAirCon,$devicesInfos{$ARGV[2]}{'idx_update'});
}
elsif ($ARGV[0] =~ /fan/ && exists $devicesInfos{$ARGV[2]}{'idx_status'}) {
   init_mel($ARGV[2]);
   debug("Send commande to device:" . $buildingID);
   $infosAirCon = getAirConInfos($contextID,$deviceID,$buildingID);
   setMELDeviceFan($contextID,$ARGV[1],$infosAirCon,$devicesInfos{$ARGV[2]}{'idx_update'});
}
elsif ($ARGV[0] =~ /power/ && exists $devicesInfos{$ARGV[2]}{'idx_status'}) {
   init_mel($ARGV[2]);
   $infosAirCon = getAirConInfos($contextID,$deviceID,$buildingID);
   setMELDevicePower($contextID,$ARGV[1],$infosAirCon,$devicesInfos{$ARGV[2]}{'idx_update'});
}
elsif ($ARGV[0] =~ /mode/ && exists $devicesInfos{$ARGV[2]}{'idx_status'}) {
   init_mel($ARGV[2]);
   $infosAirCon = getAirConInfos($contextID,$deviceID,$buildingID);
   setMELDeviceMode($contextID,$ARGV[1],$infosAirCon,$devicesInfos{$ARGV[2]}{'idx_update'});
}
elsif ($ARGV[0] =~ /vanevertical/ && exists $devicesInfos{$ARGV[2]}{'idx_status'}) {
   init_mel($ARGV[2]);
   $infosAirCon = getAirConInfos($contextID,$deviceID,$buildingID);
   setMELDeviceVaneVertical($contextID,$ARGV[1],$infosAirCon,$devicesInfos{$ARGV[2]}{'idx_update'});
}
elsif ($ARGV[0] =~ /vanehorizontal/ && exists $devicesInfos{$ARGV[2]}{'idx_status'}) {
   init_mel($ARGV[2]);
   $infosAirCon = getAirConInfos($contextID,$deviceID,$buildingID);
   setMELDeviceVaneHorizontal($contextID,$ARGV[1],$infosAirCon,$devicesInfos{$ARGV[2]}{'idx_update'});
}
elsif ($ARGV[0] =~ /help/) {
   print "-------------------------- MELCLOUD PERL FOR DOMOTICZ v0.4 --------------------------\n";
   print "report: send status of devices to domoticz. Use it for crontab\n";
   print "power on/off DEVICENAME: power on or off a device.\n";
   print "mode modename DEVICENAME: choose mode warm,dry,cool,vent or auto\n";
   print "temp T° DEVICENAME: set temperature device. \n";
   print "fan FAN_SPEED DEVICENAME: set fan speed of the device. \n";
   print "vanevertical VANE_POS DEVICENAME: set van position to 1 - 5, 0 to auto and 7 to move . \n";
   print "vanehorizontal VANE_POS DEVICENAME: set van position to 1 - 5, 0 to auto and 12 to move . \n";
   print "more to come...\n";
}
else {
   print "Nothing to do. Type help for help ;)\n";
}
Image

Re: [Perl] Control Mitsubishi MAC-557IF-E airconditioning

Posted: Tuesday 15 March 2016 20:05
by bran2000
Hi,
since the last time i progress, i tried the version 0.4 :
i have this error now :
pi@DomoticzSam ~/domoticz/scripts $ perl melcloud2.pl power off CUISINE
context ID: 733C65BA34AF4F64A268FBF64FE79B
getairconinfos : 733C65BA34AF4F64A268FBF64FE79B
'"' expected, at character offset 4 (before "Success: false, Erro...") at melcloud2.pl line 297.

the line 297 in your script :
my $decoded = JSON->new->utf8(0)->decode($json);

any idea how i can fix this ?
Thanks