sburke781 / hubitat

Hubitat apps and device drivers
8 stars 8 forks source link

MEL - Local Control #40

Open sburke781 opened 3 years ago

sburke781 commented 3 years ago

Expand the Unified Thermostat Drivers to include local control of air conditioning units, removing the reliance on the cloud services.

sburke781 commented 3 years ago

Following communications issues for @bikesquid in recent days, I have taken another look at Fraser Sim's Typescript example for Homebridge and have made some note's on the encode token method:

// calcuate a token - based on pykumo and homebridge-kumo-local
const W = this.h2l(KUMO_KEY);
const p = base64.decode(password);

const data_hash = sjcl.codec.hex.fromBits(
  sjcl.hash.sha256.hash(
    sjcl.codec.hex.toBits(
      this.l2h(
        Array.prototype.map.call(p + post_data, (m2) => {
          return m2.charCodeAt(0);
        }),
      ),
    ),
  ),
);
// convert data_hash to byteArray
const data_hash_byteArray = this.h2l(data_hash);

// Part # 1 - Decode the password

const p = base64.decode(password);

Returns a byte[] or string(?) of decoded password string from Kumo

// Encode def encoded = text.bytes.encodeBase64().toString() println encoded

// Decode byte[] decoded = encoded.decodeBase64() println new String(decoded)

// Part # 2

SHA256 Hash

Could originalString below just be = password.decodeBase64() + post_data

MessageDigest digest = MessageDigest.getInstance("SHA-256"); byte[] encodedhash = digest.digest( originalString.getBytes(StandardCharsets.UTF_8));

producing data_hash_byteArray from Typescript example

// Part # 3

Mashing together data_hash_byteArray, Kumo Key and CryptoSerial

const intermediate = new Uint8Array(88); for (let i = 0; i < 32; i++) { intermediate[i] = W[i]; intermediate[i + 32] = data_hash_byteArray[i]; } intermediate[64] = 8; intermediate[65] = 64; intermediate[66] = 0; //S_PARAM

// convert cryptoSerial to byte array
const cryptoserial = this.h2l(cryptoSerial);

intermediate[79] = cryptoserial[8];
for (let i = 0; i < 4; i++) {
  intermediate[i + 80] = cryptoserial[i + 4];
  intermediate[i + 84] = cryptoserial[i];
}

This should all translate easily as quivalent array manipulation in Groovy

// Part # 4

Do SHA-256 hash of intermediate Byte array

const hash = sjcl.codec.hex.fromBits( sjcl.hash.sha256.hash(sjcl.codec.hex.toBits(this.l2h(intermediate))), ); return hash;

Use Message Digest again.... Without needing to convert a string to a byte array

MessageDigest digest = MessageDigest.getInstance("SHA-256"); byte[] encodedhash = digest.digest( originalString.getBytes(StandardCharsets.UTF_8));

Convert encodedHash[] to Hex String

private static String bytesToHex(byte[] hash) { StringBuilder hexString = new StringBuilder(2 * hash.length); for (int i = 0; i < hash.length; i++) { String hex = Integer.toHexString(0xff & hash[i]); if(hex.length() == 1) { hexString.append('0'); } hexString.append(hex); } return hexString.toString(); }