Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

code 403: "message":"Have no authority to the request","code":4300 #70

Open
penavarr opened this issue Oct 12, 2022 · 34 comments
Open

code 403: "message":"Have no authority to the request","code":4300 #70

penavarr opened this issue Oct 12, 2022 · 34 comments

Comments

@penavarr
Copy link

Hello,

I'm getting an error when trying to run the Module example, in this step:
print(session.get_device(devices[0]['id']))

I get:
Traceback (most recent call last):
File "C:\Users\Pete\Documents\Programacion\Python\test1.py", line 73, in
print(session.get_device(devices[0]['id']))
File "C:\Program Files\Python310\lib\site-packages\pcomfortcloud\session.py", line 273, in get_device
raise ResponseError(response.status_code, response.text)
pcomfortcloud.session.ResponseError: Invalid response, status code: 403 - Data: {"message":"Have no authority to the request","code":4300}

I've tried to change the init to use verifySsl=False (I saw that in one of the issues):
def init(self, username, password, tokenFileName='~/.panasonic-token', raw=True, verifySsl=False):
but no luck.

Thanks in advance

@lostfields
Copy link
Owner

Sound strange, are you able to use the same user inn the app?

@penavarr
Copy link
Author

Hello,
I'm using the same credentials.
image
image

The strange thing is that no matter the email and password (right or wrong), I can always retrieve the list of devices, and I always end up getting the same 4300 error:
image

Maybe the session is stuck with old wrong credentials? Or I'm retrieving a dummy list of devices?

@lostfields
Copy link
Owner

I may take a look, are you sure you have installed the latest version?

@penavarr
Copy link
Author

I think so:
image
Unless I'm missing something

@lostfields
Copy link
Owner

May you try to download VS Code and try to run some of the requests in https://github.com/lostfields/python-panasonic-comfort-cloud/blob/master/requests.http - you may use curl as well, but you have to rewrite them.

VS Code + REST Client may run these commands in sequence.

First login, by running the first request. Then run the second one to get the first device in the device list. After that you can run anyone of them, to see if any fails.

@penavarr
Copy link
Author

penavarr commented Oct 22, 2022

I've tried, and in the 3rd call I get the 4300 "Have no authority to the request".
Here you have the results of the 3 first calls:

GET https://accsmart.panasonic.com/device/group HTTP/1.1

HTTP/1.1 200 
Date: Sat, 22 Oct 2022 06:03:37 GMT
Content-Type: application/json;charset=utf-8
Transfer-Encoding: chunked
Connection: close
Server: nginx
Cache-Control: no-store,no-cache,must-revalidate,max-age=0
Pragma: no-cache
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
X-XSS-Protection: 1;mode=block
Strict-Transport-Security: max-age=31536000;includeSubdomains
Content-Security-Policy: script-src 'self' 'unsafe-inline'

{
  "result": 0,
  "uToken": "***",
  "country": "ES",
  "extUsrId": "***",
  "clientId": "***",
  "language": 0
}

GET https://accsmart.panasonic.com/deviceStatus/now/{{device.response.body.$.groupList[0].deviceList[0].deviceGuid}} HTTP/1.1

HTTP/1.1 200 
Date: Sat, 22 Oct 2022 06:04:03 GMT
Content-Type: application/json;charset=utf-8
Transfer-Encoding: chunked
Connection: close
Server: nginx
Cache-Control: no-store,no-cache,must-revalidate,max-age=0
Pragma: no-cache
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
X-XSS-Protection: 1;mode=block
Strict-Transport-Security: max-age=31536000;includeSubdomains
Content-Security-Policy: script-src 'self' 'unsafe-inline'

{
  "iaqStatus": {
    "statusCode": 200
  },
  "a2wStatus": {
    "statusCode": 200
  },
  "uiFlg": false,
  "groupCount": 1,
  "groupList": [
    {
      "groupId": 773894,
      "groupName": "My House",
      "pairingList": [],
      "deviceList": [
        {
          "deviceGuid": "B308306902",
          "deviceType": "2",
          "deviceName": "Aerotermia",
          "connectionStatus": 0,
          "operationMode": 1,
          "zoneStatus": [
            {
              "zoneId": 1,
              "operationStatus": 0,
              "temperature": 37
            },
            {
              "zoneId": 2
            }
          ],
          "tankStatus": {
            "operationStatus": 0,
            "temperature": 56
          },
          "parameters": {}
        }
      ]
    }
  ]
}

GET https://accsmart.panasonic.com/deviceStatus/{{device.response.body.$.groupList[0].deviceList[0].deviceGuid}} HTTP/1.1

HTTP/1.1 403 
Date: Sat, 22 Oct 2022 06:04:33 GMT
Content-Type: application/json;charset=UTF-8
Content-Length: 58
Connection: close
Server: nginx
Cache-Control: no-cache, must-revalidate

{
  "message": "Have no authority to the request",
  "code": 4300
}

@lostfields
Copy link
Owner

This is really a authorization problem, since you get HTTP 403. Are you sure you don't have to agree to some terms when you use your credentials in the the Panasonic Comfort Cloud app at your phone?

If you have several users, may you log into with your primary user, and press the upper icon at right, and going into Owner > User list and make sure everyone has access?

@riskorte
Copy link

Hi,

Was the root cause for this identified, have been facing exactly same issue for several users including primary user. I get the user and device information, but all other calls eg. dump, history are failing with {"message":"Have no authority to the request","code":4300}, Have two mobile apps and both are working fine.

@os11k
Copy link

os11k commented Apr 12, 2023

Hi! I'm having same issue, any hint?

@os11k
Copy link

os11k commented Apr 14, 2023

Anyone, please!

I'm still getting:

{"message":"Have no authority to the request","code":4300}

@lostfields

@penavarr
Copy link
Author

I never managed to fix this problem :(

@os11k
Copy link

os11k commented Apr 15, 2023

Just to update, my guess is that seems this script does not work with some panasonic devices, for myself I see solution just to use curl instead, what seems to work fine for purposes I need(I want turn on or off devices based on spot prices of electricity).

@lostfields
Copy link
Owner

lostfields commented Apr 15, 2023

What kind of curl command line works for you? @os11k

@os11k
Copy link

os11k commented Apr 15, 2023

sent an email @lostfields

@penavarr
Copy link
Author

Hi @os11k,
I can't get this to work. Can you please send me the solution you built with curl? It'd be very appreciated.
Thanks a lot in advance!

@penavarr
Copy link
Author

@lostfields is there any advance on this?

@lostfields
Copy link
Owner

Hmm, try to do a new request to https://accsmart.panasonic.com/deviceStatus/now/ and after that find the deviceGuid in the response body and insert it into the following url at the end replacing # ; https://accsmart.panasonic.com/deviceStatus/now/#

@penavarr
Copy link
Author

penavarr commented Oct 16, 2023 via email

@penavarr
Copy link
Author

I just noticed, even if I use a dummy user and password in the Session:
session = pcomfortcloud.Session('aaa', 'xxxx')
It still prints the devices correctly:
print(devices)

[{'id': 'f0de1ca618eeaeb66acc19a0b73b27a6', 'name': 'Aerotermia', 'group': 'Huetor', 'model': ''}]

But then, when trying to get the info from the device, it yields the error:
print(session.get_device(devices[0]['id']))

pcomfortcloud.session.ResponseError: Invalid response, status code: 403 - Data: {"code":4300,"message":"Have no authority to the request"}

Could it be that the user and password are stored and hardcoded somewhere, and that it has to be cleaned?

@lostfields
Copy link
Owner

lostfields commented Oct 16, 2023

it stores the session token in ~/.panasonic-token at

def __init__(self, username, password, tokenFileName='~/.panasonic-token', raw=False, verifySsl=True):

But it should try to auth again if the authorization fails. It will not authorize again if some of the commands fails though.

except ResponseError:
if self._raw: print("--- token probably expired")
self._vid = None
self._devices = None
os.remove(self._tokenFileName)
if self._vid is None:
self._create_token()

If I try GET https://accsmart.panasonic.com/deviceStatus/now without deviceGuid it will fail with 403 at my end as well.

The following requests works just fine at my part;

GET https://accsmart.panasonic.com/device/group HTTP/1.1
X-User-Authorization: {{login.response.body.$.uToken}}
X-APP-TYPE: 1
X-APP-VERSION: {{APP-VERSION}}
X-APP-TIMESTAMP: 1
X-APP-NAME: Comfort Cloud
X-CFC-API-KEY: Comfort Cloud
User-Agent: G-RAC
Accept: application/json; charset=utf-8
Content-Type: application/json; charset=utf-8

and next GET https://accsmart.panasonic.com/deviceStatus/now/CS-HZ25UKE-5+4948102813 works as well. That is my deviceGuid, yours is different.

@penavarr
Copy link
Author

penavarr commented Oct 16, 2023 via email

@penavarr
Copy link
Author

penavarr commented Oct 16, 2023 via email

@lostfields
Copy link
Owner

My deviceType is 3. So I guess there is some different device family at Panasonic that has different APIs. Until someone figure out how to communicate with this device family I guess we are kinda out of luck.

@lobster156
Copy link

Hello,
I have the same issue.
My objective is to get the power consumption of my heater pump via a script.
Is there any way that works today to get this data?
Thanks in advance !

@os11k
Copy link

os11k commented Dec 6, 2023

Hello, I have the same issue. My objective is to get the power consumption of my heater pump via a script. Is there any way that works today to get this data? Thanks in advance !

Hi, It is possible for sure. I don't have it in my script, which I use just for on/off heater and tank.

But here a bit more clues how to do that:

cjaliaga/home-assistant-aquarea#1 (comment)

https://community.home-assistant.io/t/panasonic-aquarea-heat-pump-integration/392095/110

I plan to put my script for switching heating and tank in github soon, but unfortuantly I don't have time for that now.

So if I was you, I would login into aquare cloud and download data, unfortunately I can't recall what file name it is.

Logging in and out and control heat pump is very trivial task to do.

@lobster156
Copy link

Are you sure web scrapping is possible on aquarea smart cloud? It seems like it is not allowed, and there is a layer of protection to avoid it. When I made a simple python script to attempt this, the querry got rejected...

@os11k
Copy link

os11k commented Dec 6, 2023

I'm able to login and control my heat pump, I didn't tried to scrap any data, but seems this project will be able to do it:

https://github.com/cjaliaga/home-assistant-aquarea

More details:

cjaliaga/aioaquarea@baf98ea

I doubt that it is impossible to scrap that data, but again I didn't try to do it by myself, so I can't be 100% sure.

I will wait for @cjaliaga release, I use his integration in my home assistant to push data to influxDB, like tank temperature and etc. I control heat pump by my own scripts, I was not able to migrate that functionality in homeassistant yet, but I think this will be an endgame for me.

@os11k
Copy link

os11k commented Dec 6, 2023

Just to add a it more on this. I'm using this integration:

https://github.com/cjaliaga/home-assistant-aquarea

And I'm able to get temperature data as outside temperature, tank temperature and much more, only power consumption is not supported yet, but seems it will be done very soon.

@lobster156
Copy link

Thanks a lot!
It seems like getting the aioaquarea to work from a Synology NAS is not going to be straight forward, right?
And via the pcomfortcloud.py, will there be a fix soon?

@os11k
Copy link

os11k commented Dec 6, 2023

Never tried, but seems it is possible to install home assistant on Synology NAS

@bscrivo
Copy link

bscrivo commented Jan 16, 2024

Same error for me using aquarea comfort cloud. Do you guys found the solution?
Edit
Ok some considerations based on what I understood

  1. This library is using accsmart.panasonic.com as server for requests
  2. I'm trying to control my Panasonic Aquarea. get_devices works properly, get_device(devices[0]['id']) return the error 403
  3. Same situation using VS code + REST Client for manually sending requests
  4. Debugging the code, it seems that the issue is not caused by wrong token, or lost session or other stuff like that

It seems (also reading your comments) that the error is caused by some differences between different families of Panasonic devices. In my case, the response to the request https://accsmart.panasonic.com/device/group is
{ "a2wStatus": { "statusCode": 200 }, "uiFlg": false, "groupCount": 1, "groupList": [ { "groupId": ***, "groupName": "My House", "pairingList": [], "deviceList": [ { "deviceGuid": "***", "deviceType": "2", "deviceName": "Aquarea ", "connectionStatus": 0, "operationMode": 1, "zoneStatus": [ { "zoneId": 1, "operationStatus": 1, "temperature": 19 }, { "zoneId": 2 } ], "tankStatus": { "operationStatus": 1, "temperature": 45 } } ] } ] }

In particular, consider "deviceType": "2". For that family there may be different API requests to be done.
I'd like to help you in fixing that, so I was trying to understand what kind of requests should be made for my device. But unfortunately I didn't find anything really helpful.
Now my question is, where did you find the requests that need to be made for the devices for which this library works?

@bscrivo
Copy link

bscrivo commented Jan 17, 2024

I have some updates to share. I attempted to sniff the HTTP traffic on my Comfort Cloud app for my Aquarea, and here is what I observed:
Screenshot from 2024-01-17 10-23-04

It appears that certain requests are directed to https://accsmart.panasonic.com/, while others are directed to https://aquarea-smart.panasonic.com/. Specifically, the token is acquired when interacting with accsmart.panasonic.com, and the remaining requests are directed to https://aquarea-smart.panasonic.com/.

In the provided example, I issued a temperature change command for zone 1. The request was submitted via POST to the following URL: https://aquarea-smart.panasonic.com/remote/v1/api/devices/{deviceGuid}

The JSON request body is:
{ "status": [ { "deviceGuid": "***", "zoneStatus": [ { "zoneId": 1, "heatSet": 18 } ] } ] }

The requests forwarded to aquarea-smart.panasonic.com do not employ the same method for obtaining authorization as utilized in this library (X-User-Authorization: {{login.response.body.$.uToken}}). The exact mechanism they employ remains somewhat unclear to me, but it appears to involve the use of cookies.

I would like to know if the same information can be obtained/sent by sending requests to accsmart.panasonic.com instead of aquarea-smart.panasonic.com.

@os11k
Copy link

os11k commented Jan 17, 2024

I don't change temperature, but I just enable/disable heating or water tank heating. All what I do I login to https://aquarea-smart.panasonic.com/remote/v1/api/auth/login and update heat/water tank using https://aquarea-smart.panasonic.com/remote/v1/api/devices/$selectedDeviceId and then logout with https://aquarea-smart.panasonic.com/remote/v1/api/auth/logout.

I do get cookie string from Set-Cookie header during login and then I use it for logout and on/off heating...

In your case I would look for same request, try to sniff login, get cookie and then try to update as needed your setting. Keep in mind, logout is mandatory, otherwise your smart cloud adapter will hang up and will become unresponsive.

I run this script with arguments:

# heating on tank on   1 1
# heating off tank on  0 1
# heating on tank off  1 0
# heating off tank off 0 0

like ./script.pl 1 1 to enable heating and water tank heating

check more details for my code, part for sending telegram message can be omitted:

#!/usr/bin/perl

use strict;
use warnings;
use LWP::UserAgent;
use Time::Piece;
use HTTP::Request::Common qw(POST);

my $username = 'zzz';
my $pass = "aaaa";
my $token="vvvv";
my $chatid="bbbb";

my $selectedGwid = "ffff";
my $selectedDeviceId = "dddd";
my $JSESSIONID = "kkk";

my $h = shift @ARGV;
my $t = shift @ARGV;

sub login {
  my ($url, $username, $password) = @_;
  my $epoch_time_in_ms = time * 1000;
  my $cookie_header = "cp%3Amanual%3Acb-fv%3Aclose=Yes; selectedGwid=$selectedGwid; selectedDeviceId=$selectedDeviceId; operationDeviceTop=1; deviceControlDate=$epoch_time_in_ms; JSESSIONID=$JSESSIONID";

  my $ua = LWP::UserAgent->new;
  $ua->agent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36');
  $ua->default_header('Accept' => '*/*');
  $ua->default_header('Accept-Encoding' => 'gzip, deflate, br');
  $ua->default_header('Accept-Language' => 'en-US,en;q=0.9');
  $ua->default_header('Connection' => 'keep-alive');
  $ua->default_header('Content-Type' => 'application/x-www-form-urlencoded; charset=UTF-8');
  $ua->default_header('Cookie' => $cookie_header);
  $ua->default_header('Host' => 'aquarea-smart.panasonic.com');
  $ua->default_header('Origin' => 'https://aquarea-smart.panasonic.com');
  $ua->default_header('Popup-Screen-Id' => '1001');
  $ua->default_header('Referer' => 'https://aquarea-smart.panasonic.com/');
  $ua->default_header('Registration-Id' => '');
  $ua->default_header('Sec-Fetch-Dest' => 'empty');
  $ua->default_header('Sec-Fetch-Mode' => 'cors');
  $ua->default_header('Sec-Fetch-Site' => 'same-origin');
  $ua->default_header('X-Requested-With' => 'XMLHttpRequest');

  my $response = $ua->post(
    $url,
    Content => { 'var.inputOmit' => 'false', 'var.loginId' => $username, 'var.password' => $password }
  );

#  print "Request Headers:\n";
#  print $response->request->headers->as_string, "\n";
#  print "Request Body:\n";
#  print $response->request->content, "\n";
#  print "Response Headers:\n";
#  print $response->headers->as_string, "\n";
#  print "Response Body:\n";
#  print $response->content, "\n";
   my @set_cookie_arr = $response->header('Set-Cookie');

#  print $response->header('Set-Cookie'), "\n\n\n";
#  print $set_cookie_arr[2], "\n\n\n";

  return ($response->code, join("", @set_cookie_arr));
}

sub extract_access_token {
  my ($cookie_header) = @_;

  my ($access_token) = $cookie_header =~ /accessToken=([^;]+)/;

  return $access_token;
}

sub update {
  my ($access_token, $heating, $tank) = @_;
  my $epoch_time_in_ms = time * 1000;
  my $cookie_header = "selectedGwid=$selectedGwid; selectedDeviceId=$selectedDeviceId; operationDeviceTop=1; deviceControlDate=$epoch_time_in_ms; accessToken=$access_token; JSESSIONID=$JSESSIONID";
  my $url = "https://aquarea-smart.panasonic.com/remote/v1/api/devices/$selectedDeviceId";

  my $ua = LWP::UserAgent->new;
  $ua->agent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36');
  $ua->default_header('authority' => 'aquarea-smart.panasonic.com');
  $ua->default_header('Accept' => 'application/json, text/javascript, */*; q=0.01');
  $ua->default_header('Accept-Language' => 'en-US,en;q=0.9');
  $ua->default_header('Content-Type' => 'application/json');
  $ua->default_header('Cookie' => $cookie_header);
  $ua->default_header('Origin' => 'https://aquarea-smart.panasonic.com');
  $ua->default_header('Referer' => 'https://aquarea-smart.panasonic.com/remote/a2wStatusDisplay');
  $ua->default_header('sec-ch-ua' => '"Google Chrome";v="111", "Not(A:Brand";v="8", "Chromium";v="111"');
  $ua->default_header('sec-ch-ua-mobile' => '?0');
  $ua->default_header('sec-ch-ua-platform' => '"Windows"');
  $ua->default_header('Sec-Fetch-Dest' => 'empty');
  $ua->default_header('Sec-Fetch-Mode' => 'cors');
  $ua->default_header('Sec-Fetch-Site' => 'same-origin');
  $ua->default_header('User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36');
  $ua->default_header('X-Requested-With' => 'XMLHttpRequest');

# all switched off     0, 0
# all switched on      1, 1, 1, -1
# tank off, heating on 1, 1, 0, -1
# tank on, heating off 1, 0, 1,  0
  my $operation;

  if ($heating == 0) {
    $operation = 0;
  } else {
    $operation = -1;
  }

  my $main_operation;

  if ($heating == 1 || $tank == 1) {
    $main_operation = 1;
  } else {
    $main_operation = 0;
  }

  my $response;

if ($heating == 0 && $tank == 0) {
  $response = $ua->post(
    $url,
    Content => '{"status":[{"deviceGuid":"'.$selectedDeviceId.'","operationStatus":0,"zoneStatus":[{"zoneId":1,"operationStatus":0},{"zoneId":2,"operationStatus":0}]}]}'
  );
} else {
  $response = $ua->post(
    $url,
    Content => '{"status":[{"deviceGuid":"'.$selectedDeviceId.'","operationStatus":'.$main_operation.',"zoneStatus":[{"zoneId":1,"operationStatus":'.$heating.'},{"zoneId":2,"operationStatus":0}],"tankStatus":[{"operationStatus":'.$tank.'}],"operationMode":'.$operation.'}]}'
  );
}

#  print "Request Headers:\n";
#  print $response->request->headers->as_string, "\n";
#  print "Request Body:\n";
#  print $response->request->content, "\n";
#  print "Response Headers:\n";
#  print $response->headers->as_string, "\n";
#  print "Response Body:\n";
#  print $response->content, "\n";

  return $response->code;
}

sub logout {
  my ($access_token) = @_;

  my $epoch_time_in_ms = time * 1000;
  my $cookie_header = "selectedGwid=$selectedGwid; selectedDeviceId=$selectedDeviceId; operationDeviceTop=1; JSESSIONID=$JSESSIONID; accessToken=$access_token; deviceControlDate=$epoch_time_in_ms;";
  my $url = 'https://aquarea-smart.panasonic.com/remote/v1/api/auth/logout';

  my $ua = LWP::UserAgent->new;
  $ua->agent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36');
  $ua->default_header('authority' => 'aquarea-smart.panasonic.com');
  $ua->default_header('Accept' => '*/*');
  $ua->default_header('Accept-Language' => 'en-US,en;q=0.9');
  $ua->default_header('Connection' => 'keep-alive');
  $ua->default_header('Content-Length' => '0');
  $ua->default_header('Cookie' => $cookie_header);
  $ua->default_header('Origin' => 'https://aquarea-smart.panasonic.com');
  $ua->default_header('Popup-Screen-Id' => '1008');
  $ua->default_header('Referer' => 'https://aquarea-smart.panasonic.com/remote/a2wStatusDisplay');
  $ua->default_header('Registration-Id' => '');
  $ua->default_header('sec-ch-ua' => '"Google Chrome";v="111", "Not(A:Brand";v="8", "Chromium";v="111"');
  $ua->default_header('sec-ch-ua-mobile' => '?0');
  $ua->default_header('sec-ch-ua-platform' => '"Windows"');
  $ua->default_header('Sec-Fetch-Dest' => 'empty');
  $ua->default_header('Sec-Fetch-Mode' => 'cors');
  $ua->default_header('Sec-Fetch-Site' => 'same-origin');
  $ua->default_header('X-Requested-With' => 'XMLHttpRequest');

  my $response = $ua->post($url);

#  print "Request Headers:\n";
#  print $response->request->headers->as_string, "\n";
#  print "Request Body:\n";
#  print $response->request->content, "\n";
#  print "Response Headers:\n";
#  print $response->headers->as_string, "\n";
#  print "Response Body:\n";
#  print $response->content, "\n";

  return $response->code;
}


sub send_telegram_message {
    my ($token, $chat_id, $message) = @_;

    my $ua = LWP::UserAgent->new;
    my $url = "https://api.telegram.org/bot$token/sendMessage";
    my $req = POST $url, [
        chat_id => $chat_id,
        text => $message,
    ];
    my $res = $ua->request($req);

    if ($res->is_success) {
        print "Message sent successfully.\n";
    } else {
        print "Error sending message: ", $res->status_line, "\n";
    }
}

my ($response_code, $res_cookie_header) = login('https://aquarea-smart.panasonic.com/remote/v1/api/auth/login', $username, $pass);

if ($response_code == 200) {
    my $access_token = extract_access_token($res_cookie_header);
    print "Cookie header: $res_cookie_header\n";
#    print "Access Token: $access_token\n";
    my $update_resp = update($access_token,$h,$t);
    print "Update response: $update_resp\n";
        if ($update_resp == 200) {
                #send_telegram_message($token, $chatid, "Sent command to panasonic heat $h tank $t\n");
                print "Sent command to panasonic heat $h tank $t\n";
        } else {
                send_telegram_message($token, $chatid, "Got error sending command to panasonic code $update_resp command heat $h tank $t\n");
        }
    my $logout_resp = logout($access_token);
    print "Logout response: $logout_resp\n";
} else {
    print "Error: unexpected response code $response_code\n";
    send_telegram_message($token, $chatid, "Got error authorizing in panasonic code $response_code\n");
}

@bscrivo
Copy link

bscrivo commented Jan 17, 2024

@os11k yeah, thanks for sharing that. I used a slightly different approach

import requests
import json

def get_user_token(username, password):    
    url = "https://accsmart.panasonic.com/auth/login"
    headers = {
        "X-APP-TYPE": "1",
        "X-APP-VERSION": "1.19.0",
        "X-APP-TIMESTAMP": "1",
        "X-APP-NAME": "Comfort Cloud",
        "X-CFC-API-KEY": "Comfort Cloud",
        "User-Agent": "G-RAC",
        "Accept": "application/json; charset=utf-8",
        "Content-Type": "application/json; charset=utf-8"
    }

    data = {
        "language": 0,
        "loginId": username,
        "password": password
        }

    response = requests.post(url, headers=headers, json=data)
    return json.loads(response.text)['uToken']

def get_idp_token(userToken):
    url = "https://accsmart.panasonic.com/auth/idpToken"
    headers = {
        "X-APP-TYPE": "1",
        "X-APP-VERSION": "1.19.0",
        "X-User-Authorization": userToken,
        "X-APP-TIMESTAMP": "1",
        "X-APP-NAME": "Comfort Cloud",
        "X-CFC-API-KEY": "Comfort Cloud",
        "User-Agent": "G-RAC",
        "Accept": "application/json; charset=utf-8",
        "Content-Type": "application/json; charset=utf-8",
    }

    response = requests.get(url, headers=headers)
    return json.loads(response.text)['idpToken']


def get_session_cookies(idpToken, gwid):
    url = "https://aquarea-smart.panasonic.com/"
    headers = {
        "Accept": "text/html,application/xhtml+xml,application/xml",
        "Accept-Encoding": "gzip, deflate",
        "Connection": "keep-alive",
        "Content-Type": "application/x-www-form-urlencoded",
        "Host": "aquarea-smart.panasonic.com",
        "User-Agent": "G-RAC",
        "X-Requested-With": "com.panasonic.ACCsmart"
    }

    data = {
        "X-Authorization": idpToken,
        "cfcLoginMode": "1",
        "gwid": gwid
    }

    response = requests.post(url, headers=headers, data=data)
    return response.cookies

def set_temperature(cookies):
    device_guid = cookies.get('selectedDeviceId', None)
    url = f"https://aquarea-smart.panasonic.com/remote/v1/api/devices/{device_guid}"
    headers = {
        "Accept": "application/json, text/javascript, */*; q=0.01",
        "Accept-Encoding": "gzip, deflate",
        "Connection": "keep-alive",
        "Content-Type": "application/json",
        "Host": "aquarea-smart.panasonic.com",
        "Origin": "https://aquarea-smart.panasonic.com",
        "Referer": "https://aquarea-smart.panasonic.com/remote/a2wControl",
        "User-Agent": "G-RAC",
        "X-Requested-With": "XMLHttpRequest"
    }
    headers["Cookie"] = "; ".join([f"{cookie.name}={cookie.value}" for cookie in cookies])

    data = {
        "status": [
            {
            "deviceGuid": device_guid,
            "tankStatus": [
                {
                "heatSet": 45
                }
            ]
            }
        ]
    }
    response = requests.post(url, headers=headers, json=data)
    return response

if __name__ == "__main__":
    user_email = "***"
    user_password = "***"
    device_guid = "***"

    user_token = get_user_token(user_email, user_password)
    idp_token = get_idp_token(user_token)
    cookies = get_session_cookies(idp_token, device_guid)
    set_temperature(cookies)

I find this a nice approach, as it mirrors the one used in version 1.19.0 of the Comfort Cloud app. Obviously, the same approach could be used for other settings or to retrieve data from the Aquarea.

One important consideration is to minimize the frequency of calls to get_user_token, as it may lead to server blockages. Following the existing approach in this library is advisable: store the token and only recreate it when it has expired.

In your case I would look for same request, try to sniff login, get cookie and then try to update as needed your setting. Keep in mind, logout is mandatory, otherwise your smart cloud adapter will hang up and will become unresponsive.

Tbh, I never experienced that. I never did a log-out but my adapter still remained responsive.

Now it would be awesome to integrate that on this library.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants