From 062acb6ac829c2593663e66258827b4cc93e940e Mon Sep 17 00:00:00 2001 From: Christopher Mullins Date: Sat, 22 Jun 2019 14:58:51 -0700 Subject: [PATCH 01/17] Add setting for HASS discovery prefix --- dist/index.html.gz.h | 4 ++-- lib/Settings/Settings.cpp | 2 ++ lib/Settings/Settings.h | 1 + web/src/js/script.js | 6 ++++++ 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/dist/index.html.gz.h b/dist/index.html.gz.h index 2a614a9e..a0d4cb25 100644 --- a/dist/index.html.gz.h +++ b/dist/index.html.gz.h @@ -1,2 +1,2 @@ -#define index_html_gz_len 11302 -static const char index_html_gz[] PROGMEM = {31,139,8,0,0,0,0,0,0,19,237,125,107,119,219,56,146,232,247,251,43,96,166,39,38,219,20,37,219,177,147,200,166,178,110,219,233,120,55,15,111,236,116,239,30,143,175,14,36,65,22,19,138,212,144,148,31,227,214,127,223,170,2,64,130,15,217,74,58,211,219,167,239,77,207,88,36,1,2,85,133,66,189,80,0,247,215,70,241,48,187,155,9,54,201,166,97,111,31,255,178,144,71,87,190,37,34,11,238,5,31,245,246,167,34,227,108,56,225,73,42,50,223,154,103,227,214,11,40,203,130,44,20,189,119,193,219,224,106,146,177,55,243,193,126,91,62,218,15,131,232,11,75,68,232,91,105,118,23,138,116,34,68,102,177,73,34,198,190,53,201,178,89,218,109,183,167,252,118,56,138,188,65,28,103,105,150,240,25,222,12,227,105,59,127,208,222,246,182,189,231,237,97,154,22,207,188,105,0,181,210,212,82,125,148,155,188,10,50,108,5,126,38,243,129,23,196,197,123,173,44,190,186,10,69,123,203,131,255,202,77,170,162,188,229,26,220,141,93,65,63,159,83,111,24,198,243,209,56,228,137,32,208,249,103,126,219,14,131,129,217,122,26,6,35,145,180,95,122,207,189,78,165,99,89,244,125,59,78,69,40,134,89,240,79,225,125,78,219,29,111,115,203,219,165,94,139,231,121,255,219,255,50,148,169,175,246,38,246,254,172,138,51,149,61,212,51,241,90,196,167,194,183,174,3,113,51,139,19,96,157,97,28,101,34,2,222,187,9,70,217,196,31,137,235,96,40,90,116,227,6,81,144,5,60,108,165,67,30,10,127,19,154,88,107,181,46,130,49,11,51,118,114,204,94,94,246,254,15,131,127,251,233,48,9,102,25,75,147,225,202,56,225,108,216,73,39,193,53,240,226,115,111,187,184,7,234,66,63,109,217,36,182,191,191,118,33,162,81,48,190,108,181,122,251,132,79,207,195,185,35,146,86,18,223,220,15,226,4,47,7,113,150,197,211,238,230,236,150,165,49,140,62,123,50,28,14,23,33,31,136,240,126,20,164,179,144,223,117,7,97,60,252,178,240,18,62,10,226,86,60,203,130,56,186,159,241,209,40,136,174,186,29,182,51,187,221,27,206,147,52,78,186,179,56,0,162,36,11,132,121,202,163,81,107,48,135,214,163,244,62,12,210,172,69,48,116,163,56,18,123,83,158,92,5,81,183,179,151,55,83,123,135,133,65,14,64,16,193,224,139,22,193,161,222,109,37,56,197,187,155,98,186,23,95,139,100,28,198,55,93,62,207,226,133,55,142,147,105,11,70,38,185,187,215,221,176,14,219,234,0,134,29,179,148,201,107,28,199,36,14,239,105,228,186,91,29,49,45,85,42,83,194,4,68,18,9,240,201,108,79,36,73,156,56,76,254,182,130,104,28,231,175,32,190,11,179,96,24,135,64,170,68,140,246,198,208,117,43,133,25,208,245,158,99,183,69,165,238,64,0,12,226,94,49,89,119,221,94,47,21,243,49,144,185,40,117,160,84,13,237,32,139,52,218,136,242,194,187,226,153,184,225,119,45,32,52,21,2,165,120,214,37,234,45,158,168,22,152,55,74,226,217,40,190,129,113,141,211,0,7,184,171,120,184,66,221,250,27,173,169,136,230,230,96,73,226,60,129,185,53,30,7,195,86,26,5,227,113,153,26,79,232,153,24,181,84,29,0,248,182,53,17,52,160,59,29,99,68,91,119,106,76,117,103,15,13,135,23,241,235,1,79,238,7,124,248,229,42,137,231,192,74,138,212,87,3,110,63,219,116,241,127,59,174,247,210,89,11,166,56,135,121,148,237,169,89,128,172,61,79,145,11,101,35,173,65,2,172,232,150,238,186,19,4,75,13,223,147,241,120,188,240,128,158,32,62,128,36,35,14,220,86,235,24,43,169,30,170,19,204,147,160,47,193,228,102,18,100,162,149,137,233,172,53,11,134,95,160,87,69,157,45,32,78,209,77,23,223,1,240,174,16,124,24,20,59,139,25,13,172,251,132,239,142,54,199,99,214,113,17,6,182,211,249,27,94,240,78,167,195,54,59,157,191,57,123,141,51,75,79,198,109,57,85,38,115,209,208,189,156,39,216,202,94,69,62,20,245,129,73,163,166,183,64,28,14,109,124,149,181,216,182,152,46,1,163,44,76,86,194,23,102,147,196,21,240,219,245,118,119,119,159,3,194,29,184,219,6,141,13,255,232,78,209,161,211,25,179,221,188,210,24,238,94,232,74,216,12,209,71,34,115,205,67,248,171,96,188,175,15,36,144,83,75,163,80,140,179,174,183,147,99,138,56,27,232,55,15,243,44,156,167,45,208,59,240,23,17,156,221,151,230,154,73,233,97,8,120,119,65,86,79,170,68,175,182,193,164,248,236,142,131,4,68,110,60,110,161,37,85,22,246,82,116,230,60,175,231,64,22,207,170,37,82,86,32,110,171,118,27,242,165,189,98,51,141,157,150,11,30,235,200,35,131,78,183,173,104,132,12,171,155,84,115,15,102,153,126,34,21,15,13,90,206,227,160,181,152,254,255,115,208,96,185,70,82,163,182,253,12,30,210,96,169,7,155,222,179,151,15,16,100,28,136,112,4,117,195,89,179,214,42,100,253,166,183,133,124,82,101,28,144,212,225,221,108,18,128,52,241,210,25,76,32,128,242,158,71,193,148,147,56,198,71,108,51,101,32,254,81,50,11,38,231,194,94,235,70,12,190,4,89,171,92,115,171,161,234,2,77,133,66,190,131,153,3,245,175,65,23,3,20,26,71,224,181,197,32,30,105,205,169,173,131,173,14,170,146,49,152,76,198,172,166,103,255,54,21,163,128,179,56,10,239,24,152,30,66,68,12,68,37,179,177,81,26,27,214,221,70,61,228,220,55,53,187,131,77,172,210,198,179,23,75,219,232,172,218,198,243,221,23,75,218,216,220,121,177,98,27,47,95,110,45,107,99,115,23,219,240,166,241,8,12,63,172,192,188,20,237,219,56,106,149,56,182,110,112,9,33,52,91,234,82,15,132,134,82,147,172,224,139,22,201,33,197,223,187,227,221,134,26,41,76,168,92,69,237,238,46,230,161,199,37,16,203,76,49,195,2,43,215,92,102,128,53,212,35,35,72,137,156,225,36,8,71,206,125,141,189,255,237,139,184,27,39,96,68,167,12,57,244,126,156,196,211,123,48,0,162,20,173,173,46,153,202,246,166,195,146,56,3,139,197,238,56,139,44,126,160,124,123,183,51,18,87,14,140,154,158,1,229,246,183,100,7,186,176,104,168,212,254,210,226,188,121,47,119,83,90,35,184,202,68,201,128,242,134,173,162,28,166,218,180,48,57,193,50,93,128,57,78,118,247,126,91,58,173,200,22,189,70,171,31,13,124,239,42,142,193,237,227,179,32,173,24,253,159,255,49,23,201,29,88,252,224,192,168,27,242,87,74,38,127,99,187,171,186,180,159,171,30,237,227,77,175,234,218,126,94,226,217,62,222,195,35,174,16,88,4,34,73,135,96,39,163,103,185,233,189,0,119,168,120,214,250,46,125,44,241,154,27,61,230,223,221,89,147,167,12,87,41,88,170,32,84,96,178,26,53,190,55,118,37,7,249,243,18,255,184,177,67,25,154,201,196,109,214,254,204,175,185,124,106,245,198,243,136,196,4,3,243,251,60,126,147,134,54,119,133,155,56,247,188,237,111,237,236,184,66,254,36,244,179,119,205,19,150,186,153,59,244,223,241,108,226,1,219,170,234,238,68,61,9,34,253,36,242,237,225,198,196,105,111,237,5,99,123,232,251,19,39,245,51,191,179,39,194,84,220,99,67,3,127,216,154,236,165,55,192,160,19,59,243,163,158,183,243,106,208,182,183,90,240,216,233,194,21,190,238,14,157,251,33,79,5,227,221,212,183,69,43,113,218,131,13,91,236,39,175,118,187,29,103,111,144,8,14,166,40,86,16,88,33,105,113,172,176,101,22,36,88,192,91,2,11,158,45,210,182,191,187,72,68,54,79,162,251,73,55,117,211,110,230,130,123,184,88,228,148,248,248,243,79,89,252,230,236,23,77,137,77,223,247,65,92,204,193,131,202,82,47,20,209,85,54,121,250,212,22,62,247,174,220,4,254,14,92,14,127,19,71,147,167,70,156,97,141,56,19,31,68,48,144,168,3,109,103,175,58,221,73,59,115,7,126,214,70,34,107,138,40,196,135,0,126,199,196,7,41,1,132,216,152,252,152,211,193,69,172,126,156,84,201,1,212,216,216,250,113,210,80,138,52,1,146,108,60,203,75,203,52,137,220,235,238,96,177,88,149,139,126,176,53,245,108,231,254,7,123,20,15,137,90,142,7,15,172,225,4,94,18,150,107,129,234,9,225,215,168,138,4,19,254,15,118,54,9,82,7,8,39,60,48,230,109,199,75,4,232,179,161,176,219,127,255,123,251,202,181,218,150,241,200,251,241,239,237,182,107,89,206,158,240,50,144,239,87,34,177,45,108,89,206,0,203,189,200,46,157,133,227,154,96,0,226,163,187,50,140,10,26,9,162,249,122,94,75,184,153,132,144,107,8,189,25,76,78,96,2,219,2,199,112,54,207,164,173,11,109,128,5,55,130,22,145,46,150,227,6,126,182,199,115,70,225,132,83,0,32,225,127,196,35,159,222,159,156,247,79,15,62,30,188,59,243,239,129,43,222,5,224,210,164,96,224,108,187,192,53,234,110,251,121,7,239,126,34,21,22,137,52,5,67,108,103,225,126,58,233,159,31,252,116,230,95,220,103,252,170,107,101,124,0,86,207,56,0,184,19,112,182,70,225,93,215,250,21,239,23,110,81,33,133,161,157,153,53,206,232,129,89,37,20,35,179,194,219,227,163,82,49,5,149,204,10,31,233,129,89,101,250,143,44,51,107,188,251,207,243,115,107,113,137,0,191,62,57,126,123,148,131,204,71,128,114,127,158,138,4,131,117,230,43,7,88,194,138,18,180,211,187,214,39,117,207,64,243,179,16,52,19,216,65,96,53,131,87,137,131,194,192,54,152,113,228,47,116,102,186,22,72,67,40,135,59,62,48,168,163,1,149,125,207,120,154,222,128,157,103,246,125,154,63,147,189,234,251,239,209,235,36,78,179,42,174,111,242,103,178,191,51,17,142,91,192,228,113,146,129,123,171,223,96,208,95,10,111,48,84,44,87,12,36,195,132,29,29,190,57,101,137,0,251,34,205,86,235,31,111,250,160,159,178,96,216,15,202,140,64,15,217,201,41,59,24,141,18,96,178,28,156,188,128,203,2,102,131,205,115,45,216,0,68,192,23,4,11,134,137,29,189,57,60,117,190,5,134,126,36,178,41,79,191,52,195,242,94,23,74,88,212,173,238,148,136,144,87,254,166,222,85,180,173,185,247,159,101,97,149,34,6,41,20,32,60,101,170,33,118,51,65,55,164,128,138,5,104,223,138,96,24,140,113,98,173,2,226,80,244,193,32,54,65,58,60,102,109,118,250,31,231,140,158,43,182,132,9,2,58,234,248,236,244,197,214,238,46,130,33,57,116,253,240,120,157,217,120,245,254,227,235,173,103,111,59,155,140,226,50,99,144,153,14,195,10,208,144,170,177,126,250,22,252,160,231,237,183,231,47,94,118,58,235,70,197,165,144,166,37,129,49,76,163,26,172,103,239,87,3,243,236,253,250,138,189,0,169,69,86,237,231,227,241,217,241,106,4,161,154,171,246,5,226,175,218,19,136,192,106,63,106,220,177,121,44,69,126,154,167,76,121,95,204,238,248,112,201,7,208,150,179,199,34,113,69,142,59,80,247,26,108,93,244,119,130,171,136,135,204,78,4,198,208,113,82,183,182,168,45,116,210,98,14,162,6,26,93,117,8,102,124,248,5,168,3,2,67,240,44,45,11,50,44,97,121,137,4,255,124,34,88,52,159,14,4,116,55,102,89,128,14,24,198,229,168,22,251,248,154,201,6,83,148,54,25,150,12,230,225,32,93,10,76,82,18,255,101,96,250,51,145,244,195,56,158,45,135,138,65,21,38,171,168,41,158,131,166,107,104,193,23,224,188,74,161,247,80,176,171,216,99,236,13,232,67,168,74,81,191,148,77,5,143,216,20,28,9,16,203,160,140,175,38,160,150,93,12,115,177,16,103,234,116,30,130,91,15,194,3,26,240,86,196,6,173,114,133,75,31,102,69,22,39,37,185,125,126,126,170,201,166,75,37,14,239,176,175,89,24,12,229,184,203,66,228,205,50,121,104,200,149,248,198,232,15,198,239,81,228,15,238,0,5,193,168,253,131,211,19,143,125,58,162,11,6,64,67,155,97,120,7,111,13,5,52,13,44,55,151,253,8,61,108,46,75,99,73,6,221,75,58,137,231,33,180,42,138,41,129,77,175,168,38,231,89,12,240,2,131,39,25,14,103,16,151,116,229,1,20,183,84,49,211,197,146,8,88,132,17,46,13,176,172,131,136,201,165,55,38,96,54,220,25,172,136,65,195,140,162,1,2,132,101,32,70,128,56,204,177,14,65,172,231,211,138,147,2,170,15,49,56,123,215,167,197,63,3,226,35,93,194,100,137,178,44,128,194,120,143,204,134,1,23,144,225,170,87,93,89,77,138,56,242,216,145,24,115,24,97,226,76,196,39,69,245,76,111,19,129,97,248,244,130,182,196,20,198,228,217,139,23,47,95,106,124,224,53,133,206,106,99,128,246,84,31,76,31,0,164,106,86,49,253,88,162,113,4,20,71,41,152,152,234,26,72,75,85,7,73,252,5,60,95,246,129,22,4,105,84,36,169,239,96,94,17,248,164,79,109,113,203,167,179,16,116,197,244,14,223,83,175,13,49,6,246,226,197,179,165,32,147,213,87,2,57,139,129,93,193,196,202,64,169,68,53,200,169,148,229,165,218,214,162,91,34,126,81,43,53,134,5,7,224,88,66,216,133,103,64,229,180,221,149,116,238,7,163,252,18,129,108,119,201,42,135,199,30,59,19,130,125,60,62,56,122,119,76,109,143,231,73,134,178,99,36,50,30,132,203,165,91,29,169,249,108,4,179,237,17,220,100,165,135,81,4,148,102,243,1,96,53,97,198,59,169,199,78,21,171,101,19,16,44,156,38,50,77,118,152,186,73,60,101,177,2,92,113,22,70,60,103,213,55,72,116,83,109,50,81,213,132,187,9,194,16,39,34,240,46,10,83,213,33,8,6,52,104,241,149,175,32,3,106,188,199,168,64,117,190,102,156,77,154,232,151,61,246,171,180,168,228,106,130,116,33,83,89,236,210,244,27,207,1,173,47,17,174,54,202,151,80,173,193,115,249,2,33,13,178,79,181,11,84,212,134,123,5,176,213,57,160,193,95,145,35,8,5,172,234,175,48,109,188,131,231,192,164,229,80,154,184,43,119,219,228,170,80,75,179,101,254,74,222,233,55,247,57,12,113,217,174,47,205,27,57,218,181,238,15,169,14,25,188,96,2,157,203,58,18,146,195,56,138,100,72,93,91,72,96,108,164,28,199,239,145,97,1,237,126,142,55,65,52,12,231,35,168,255,246,215,115,98,245,65,0,19,23,74,31,156,207,203,245,123,9,197,52,64,41,210,175,99,90,50,103,75,232,189,211,240,191,139,71,249,48,159,0,122,212,20,232,221,17,48,37,45,72,144,98,160,238,83,182,62,148,132,16,163,117,66,98,157,244,74,254,168,70,11,192,15,218,148,184,0,101,100,171,48,89,57,227,131,120,46,149,40,154,146,64,88,215,144,244,46,19,25,80,78,55,167,104,55,202,169,33,51,65,250,106,25,192,114,229,125,218,189,183,178,100,46,44,240,124,8,11,203,181,198,60,76,241,193,145,2,1,72,214,76,66,178,151,250,185,219,64,98,183,22,28,40,220,10,38,203,37,217,182,188,103,236,231,55,255,100,212,6,33,25,130,114,66,218,201,73,46,217,33,24,179,187,120,78,243,27,47,214,65,186,69,49,106,90,20,90,96,241,105,39,103,237,81,44,35,172,217,181,232,199,114,165,203,3,179,197,244,128,76,60,203,166,96,50,222,122,6,182,196,13,26,180,96,184,132,38,146,212,34,59,197,66,246,86,22,170,153,72,143,168,62,113,105,164,96,125,20,212,119,39,239,97,118,161,203,241,246,195,175,224,128,196,55,150,251,230,228,231,55,96,116,130,198,179,220,119,7,255,5,229,252,246,17,120,165,202,236,35,57,163,38,144,223,74,149,122,168,203,37,212,191,78,130,225,132,169,151,210,138,69,148,79,96,152,211,200,134,138,154,143,224,67,88,16,62,239,78,142,240,106,84,194,231,97,44,52,36,117,248,207,208,45,56,204,139,151,129,79,222,131,9,56,34,146,3,15,147,237,19,49,211,88,224,104,229,47,130,109,36,70,41,104,73,122,63,93,58,139,192,240,204,112,150,119,239,167,210,236,23,221,181,206,226,247,227,174,6,175,193,175,83,195,86,241,235,78,162,97,34,56,97,146,41,209,137,247,232,221,1,170,124,26,207,65,140,41,143,15,145,131,59,217,5,225,14,20,81,86,4,218,74,100,7,155,134,106,81,53,55,127,49,176,177,189,92,210,150,44,88,105,45,140,195,121,58,145,194,2,124,182,106,200,5,20,57,150,179,162,92,57,83,224,24,77,231,211,146,163,16,2,56,148,198,131,214,75,118,131,43,191,244,50,25,50,202,112,128,39,60,157,52,99,3,162,6,220,116,20,197,193,148,22,145,51,1,98,103,134,34,53,205,42,45,172,232,113,24,86,81,130,127,194,96,26,212,162,160,170,105,172,192,84,133,175,66,210,52,20,177,18,186,230,170,77,123,100,120,37,59,157,206,242,240,65,73,128,151,60,210,62,122,206,89,6,58,17,46,4,248,141,225,104,169,231,206,116,93,102,212,205,213,62,102,232,165,108,2,50,123,86,118,247,185,242,207,241,77,212,115,167,102,176,129,252,15,242,214,137,73,53,214,192,191,104,200,242,72,50,54,249,251,204,6,91,202,164,145,35,245,222,144,99,92,166,210,41,6,49,140,110,25,102,166,65,223,239,100,176,160,220,46,181,2,83,69,99,55,159,65,77,211,227,219,234,116,166,223,20,14,41,168,11,200,98,82,199,117,144,221,173,64,223,82,237,175,166,112,57,72,98,146,167,78,23,144,117,56,39,40,113,111,204,97,194,39,101,182,234,184,108,202,111,137,81,37,177,54,59,29,120,214,209,243,42,93,206,116,15,209,101,42,153,127,57,41,242,10,13,216,143,121,162,49,192,217,63,228,104,56,73,201,39,101,124,37,158,36,10,119,169,132,219,246,170,176,75,159,82,73,52,76,34,42,201,230,159,201,233,144,83,82,151,230,97,125,176,247,192,242,37,253,36,203,140,216,140,182,214,208,71,48,68,133,158,236,56,46,31,143,207,206,209,127,155,129,94,17,50,122,84,8,0,13,125,19,120,205,83,95,68,56,102,125,174,227,52,125,52,193,250,114,205,145,8,80,96,117,76,85,89,94,149,172,53,102,84,149,40,190,6,136,62,254,252,211,175,191,202,152,33,179,165,149,6,143,54,14,15,207,49,44,241,250,211,121,231,197,75,7,44,85,106,49,53,154,204,91,203,231,61,118,130,122,140,81,34,14,14,18,31,143,129,134,185,19,136,46,131,152,130,216,6,219,28,184,30,105,148,226,37,229,85,201,72,60,121,203,55,32,36,88,0,242,133,136,141,230,35,248,71,95,86,54,139,37,246,166,89,172,162,55,203,117,183,24,73,106,210,106,3,200,167,113,112,85,141,40,19,9,71,115,228,53,134,213,152,174,38,105,153,87,33,52,140,176,25,169,118,118,48,28,162,156,60,197,156,75,85,143,7,25,41,255,88,181,132,36,161,5,64,133,167,6,202,224,7,105,218,55,193,60,150,118,127,19,204,4,16,65,44,43,169,30,35,90,51,125,4,248,9,79,235,111,233,56,26,181,25,193,224,27,131,179,42,208,49,113,65,133,109,203,96,24,85,86,34,113,58,39,26,99,120,225,142,37,115,74,240,251,90,176,164,168,105,132,41,15,7,167,171,192,131,54,40,142,46,69,140,49,28,132,55,249,251,223,2,20,176,229,60,42,129,246,26,205,29,54,148,134,98,13,186,247,213,53,3,128,15,33,38,133,73,150,146,132,91,75,87,212,67,52,81,13,178,213,68,43,193,119,233,254,252,241,195,167,211,254,217,249,193,249,113,255,63,142,255,251,204,191,176,148,80,179,180,71,110,13,242,229,111,184,81,62,152,53,153,83,157,124,210,195,13,37,211,193,175,164,132,245,69,132,215,65,254,188,143,242,2,27,3,249,164,104,5,5,211,217,28,244,66,95,191,41,72,202,192,69,30,86,132,107,29,74,44,30,75,95,214,138,39,234,197,75,23,200,209,127,247,225,232,24,225,255,48,30,67,225,89,8,42,74,230,80,193,221,107,208,169,197,29,149,129,199,63,211,37,250,58,164,156,108,184,250,16,65,163,159,142,78,251,167,31,63,156,127,56,252,240,182,255,203,241,199,179,147,15,239,161,131,29,119,247,210,61,58,126,125,240,233,237,121,191,168,147,87,241,119,220,60,249,200,229,97,128,158,192,89,254,128,242,16,97,40,252,181,77,55,140,57,178,214,153,242,99,240,17,105,29,184,33,109,118,50,50,31,29,96,83,240,0,115,121,44,107,205,15,227,33,81,222,211,11,213,50,83,226,70,12,206,98,100,4,63,18,55,236,87,125,103,91,55,152,230,100,109,212,94,219,176,186,47,54,45,103,47,127,209,139,35,229,179,249,69,34,134,115,15,221,106,224,101,79,152,43,130,177,145,189,31,108,171,186,81,193,114,188,25,170,125,204,201,216,135,171,158,181,145,109,88,251,109,186,116,22,139,5,53,16,191,17,183,165,62,100,2,140,213,185,181,54,132,151,197,103,196,181,246,230,174,3,55,159,102,32,70,14,129,154,182,179,144,68,17,154,74,102,19,53,10,118,138,225,240,192,115,248,5,237,39,27,32,39,94,58,25,57,232,71,170,202,240,248,74,94,209,83,12,53,229,53,207,129,233,156,166,241,73,196,24,205,112,122,66,238,20,194,87,180,89,2,238,7,123,253,137,234,129,81,250,202,5,18,80,166,207,251,214,250,134,216,88,183,46,215,29,111,136,156,168,218,65,40,106,141,144,180,10,131,199,94,191,18,217,225,60,193,132,153,35,133,174,111,100,224,72,106,131,220,72,82,113,18,101,118,65,167,43,77,39,167,212,72,13,165,188,13,100,1,141,24,101,189,210,170,43,32,8,140,128,48,218,22,1,9,67,239,98,162,206,65,52,146,83,66,50,181,209,30,112,217,90,133,200,58,71,233,190,24,136,110,1,19,13,146,227,234,225,236,214,81,134,82,5,90,183,134,10,18,41,243,63,12,62,99,226,30,238,99,10,68,106,87,39,173,167,12,19,76,50,10,193,54,47,178,152,178,156,0,125,47,72,143,255,49,231,161,157,93,108,94,122,41,191,22,35,234,227,148,39,124,154,186,2,19,143,42,83,185,227,102,42,69,169,215,121,85,235,52,231,213,236,162,115,233,116,107,229,180,211,193,118,106,242,97,177,112,229,0,124,74,66,191,150,232,213,72,158,204,111,32,140,203,253,42,149,165,232,241,125,225,160,225,127,99,189,155,131,240,20,24,54,208,10,243,228,200,194,74,57,59,168,77,112,57,23,128,233,12,215,233,44,12,64,34,185,112,169,227,204,54,119,126,251,205,206,252,142,227,90,152,154,10,92,2,26,202,247,81,214,163,230,171,247,40,87,25,176,67,37,53,218,42,19,36,5,41,7,82,13,254,114,250,155,45,234,115,212,36,76,133,221,126,251,237,7,228,255,127,63,251,240,222,206,9,9,228,48,167,32,104,215,81,40,168,165,79,36,137,108,28,95,115,170,148,103,109,105,158,168,185,171,166,73,125,130,24,178,205,239,123,218,73,180,205,254,113,203,222,15,30,166,167,218,247,243,36,236,154,112,78,69,54,137,71,224,201,125,58,183,92,108,186,139,168,120,210,2,8,198,119,240,190,171,246,166,209,84,178,248,76,173,152,199,81,251,115,138,170,92,25,96,221,71,81,6,156,225,69,153,41,201,67,145,100,112,1,252,183,41,182,81,128,70,163,67,185,83,113,25,26,10,5,171,157,222,129,207,11,110,230,125,14,252,135,179,111,133,30,199,129,0,80,236,112,70,107,47,31,227,27,223,76,43,116,185,156,17,129,111,237,103,73,15,184,118,3,175,70,61,203,133,171,245,125,18,94,106,43,171,150,45,233,197,165,197,134,96,112,165,190,101,238,136,180,88,73,2,183,123,235,46,181,214,214,205,45,107,24,215,126,87,104,52,123,180,209,81,112,173,219,192,157,118,50,39,146,22,46,84,30,57,60,87,94,86,111,125,15,186,177,17,247,200,239,236,69,251,141,102,142,146,75,123,209,198,134,164,83,234,55,214,187,136,46,221,216,231,190,159,254,246,91,234,251,15,152,69,79,159,174,53,247,100,72,128,61,66,134,118,46,26,232,176,210,230,193,245,13,59,126,101,49,53,121,186,150,229,0,117,36,113,52,113,81,102,248,114,133,196,210,187,145,229,162,13,17,27,61,95,52,61,113,143,130,111,197,96,46,178,178,26,77,161,69,38,251,25,78,4,152,68,35,217,143,213,99,214,70,170,134,129,160,236,89,42,103,151,201,135,48,14,189,230,17,146,228,175,98,53,66,119,26,29,139,105,124,45,90,122,3,170,90,45,204,145,210,111,229,155,87,88,177,141,69,190,138,201,230,65,206,33,178,47,13,131,1,78,27,57,125,65,118,103,110,116,150,51,114,85,10,187,252,105,97,102,12,138,107,186,147,27,22,65,192,52,26,159,79,159,22,82,19,230,179,106,221,114,43,22,100,205,228,237,184,74,249,126,17,119,41,84,194,29,197,199,28,36,138,169,99,117,6,240,250,19,221,176,178,158,228,224,202,25,2,134,143,27,148,12,37,174,245,245,250,197,82,19,41,207,18,238,117,158,62,181,21,211,96,182,185,199,179,44,177,45,242,53,64,53,73,78,24,196,183,245,194,87,7,73,194,239,64,255,211,175,45,48,249,249,21,254,173,227,130,68,32,85,209,13,100,189,174,76,77,166,107,204,152,86,6,40,184,59,125,165,240,1,170,102,213,47,179,73,82,24,144,138,249,82,111,163,129,170,34,183,225,193,186,0,85,47,192,106,1,242,153,54,22,199,146,220,174,226,88,65,219,81,252,98,235,18,72,87,133,139,143,70,18,42,251,30,243,176,187,153,75,116,135,223,170,61,212,13,0,217,218,251,74,77,107,204,214,54,129,36,72,147,220,29,68,106,164,203,200,96,214,107,68,56,93,14,40,122,34,168,90,36,188,2,211,196,13,183,161,14,87,49,82,102,192,79,211,20,56,85,190,172,24,180,33,52,8,60,184,151,149,103,150,69,107,47,141,237,46,96,234,8,175,41,184,181,172,203,198,64,216,3,157,54,182,221,212,173,12,34,173,214,173,138,101,173,220,173,106,187,210,109,30,62,122,180,211,34,208,180,74,151,69,187,149,14,101,32,229,209,222,84,136,105,149,174,84,139,11,45,200,192,58,46,201,250,150,36,120,10,194,22,247,158,218,114,107,133,170,163,70,3,120,191,246,168,145,205,65,58,205,200,243,174,26,64,182,98,115,244,39,92,154,240,2,230,49,201,157,122,40,2,205,40,156,181,42,21,251,80,118,88,119,40,16,25,12,40,205,71,51,173,192,0,13,112,41,214,54,49,48,32,157,64,112,127,60,169,169,14,81,149,217,22,157,208,96,201,173,24,36,217,77,121,110,218,91,151,235,248,238,148,207,12,20,11,219,237,7,48,26,228,126,149,61,173,135,211,247,252,189,29,56,175,192,151,0,229,66,21,96,182,151,187,117,163,121,24,58,36,131,130,106,231,218,38,251,87,119,28,97,199,37,87,249,162,102,170,52,194,144,25,206,68,86,117,30,200,69,91,131,42,218,198,75,253,11,180,208,58,123,241,190,214,116,123,49,24,117,233,69,124,233,95,112,248,235,6,248,39,130,63,151,123,133,65,158,43,240,220,36,167,113,124,196,113,104,50,216,239,43,60,219,77,105,27,206,194,157,161,231,80,183,67,128,131,43,220,136,30,217,247,135,75,122,108,200,226,218,19,174,5,34,42,112,104,150,239,211,144,32,227,107,78,181,28,152,83,197,6,88,29,48,112,235,177,45,70,251,171,230,160,97,246,74,248,219,247,133,242,34,253,99,130,118,32,21,229,138,224,173,28,205,72,196,104,62,20,21,222,146,51,178,49,136,161,89,29,172,21,64,23,217,199,136,141,185,60,15,169,193,165,50,20,64,194,44,220,251,58,174,85,3,69,97,44,247,13,55,133,170,76,93,140,98,68,105,111,189,41,172,52,9,30,208,220,78,121,188,49,250,99,246,89,139,70,53,88,40,143,247,254,152,89,227,212,71,86,2,34,161,58,70,81,81,154,14,226,149,193,108,173,96,212,34,223,195,106,146,47,13,245,204,179,118,180,126,17,142,211,109,110,178,73,74,235,144,4,198,52,20,18,15,5,150,84,68,142,52,231,67,129,74,198,215,21,56,14,106,10,9,129,171,35,36,22,218,232,49,208,38,179,173,252,84,27,32,175,124,35,35,84,241,12,1,81,132,152,74,130,18,221,25,115,120,150,71,158,132,243,74,87,77,39,160,37,145,52,242,182,68,140,60,92,51,9,16,63,20,30,20,57,253,69,202,107,191,193,180,6,136,48,56,210,182,255,62,218,112,254,238,153,63,118,203,246,126,116,156,87,109,173,64,238,167,252,115,156,116,113,226,185,211,32,162,203,173,75,41,36,225,114,251,210,77,96,176,176,39,184,219,193,2,208,83,221,11,170,79,53,169,14,22,93,194,76,2,109,132,73,85,117,216,138,41,110,2,143,166,111,80,126,146,229,154,141,123,212,87,47,144,191,11,87,134,130,14,209,33,122,29,39,50,26,212,192,17,168,235,128,11,232,135,87,100,23,62,92,243,209,107,132,225,30,74,190,105,41,205,151,51,169,167,30,108,88,204,198,5,1,104,54,224,81,182,97,57,74,147,174,249,153,108,33,68,8,242,6,152,135,188,142,199,28,64,83,162,100,30,105,216,178,139,50,119,80,93,244,131,202,143,103,192,119,96,165,240,156,65,240,1,110,32,46,120,68,205,167,133,134,8,112,82,160,145,67,93,3,77,45,171,21,134,158,91,175,165,231,170,100,71,105,36,237,113,191,60,168,118,230,101,252,170,143,70,131,155,147,202,121,101,65,29,157,163,202,248,53,88,212,184,98,190,102,117,173,255,150,73,156,42,127,112,10,142,59,173,104,70,153,174,238,201,217,167,129,72,231,211,41,79,238,52,168,92,2,18,248,153,7,243,1,243,213,150,71,195,51,15,193,130,97,24,137,219,15,104,91,171,161,115,214,252,214,38,26,41,134,211,141,93,142,131,100,122,195,19,209,194,163,235,44,69,102,11,143,176,179,192,60,1,213,58,72,226,27,48,149,251,40,4,80,237,245,231,73,136,26,35,168,176,54,216,1,105,28,130,229,29,95,169,72,97,126,11,230,247,94,3,183,185,143,140,144,17,127,209,135,205,176,230,64,12,9,121,21,137,113,30,162,228,195,131,46,197,139,155,155,60,148,121,12,246,78,45,40,11,232,2,35,187,28,149,7,122,78,243,68,144,101,169,223,204,79,204,152,5,250,236,9,60,212,0,55,184,166,237,52,24,197,147,182,72,103,184,101,175,63,13,104,67,71,31,234,64,121,72,217,139,109,9,94,83,207,24,129,246,69,173,103,45,25,140,32,113,117,5,81,16,117,105,222,151,172,110,69,115,140,204,200,177,215,129,55,215,250,240,30,87,28,228,123,78,113,62,199,57,197,53,109,112,22,224,54,70,218,86,139,208,71,167,5,98,45,143,243,243,21,212,115,47,209,53,188,171,252,106,128,11,31,249,249,3,15,215,220,171,98,81,44,135,35,38,242,196,11,12,170,201,149,28,203,221,236,116,126,228,94,170,22,109,196,41,138,116,113,115,136,205,225,65,42,63,102,222,132,234,128,63,169,126,67,229,156,22,139,232,218,5,193,242,82,65,203,216,211,238,229,91,218,157,182,93,122,174,55,183,47,169,93,69,201,72,243,89,130,83,160,32,44,210,4,36,132,145,111,62,251,17,79,51,107,87,32,41,54,214,215,250,149,121,6,205,61,70,56,243,235,20,172,197,247,51,90,81,130,126,97,72,225,146,251,59,29,105,54,212,142,44,67,99,3,116,188,113,48,29,181,216,181,38,192,45,180,154,228,210,2,246,223,92,90,84,250,155,67,171,12,120,132,208,153,94,207,111,116,140,105,85,28,20,136,185,234,143,78,113,221,33,46,31,76,84,178,237,202,167,26,73,217,145,206,120,68,141,72,129,114,70,91,252,52,44,22,193,6,79,190,22,184,206,163,192,41,98,53,1,39,225,110,4,46,158,25,176,145,232,43,157,121,152,107,58,92,64,139,144,219,196,145,50,248,94,99,252,107,201,194,205,178,101,143,96,164,77,204,101,43,32,224,124,115,79,39,141,191,42,66,187,106,91,133,94,81,100,102,104,58,107,8,162,114,189,54,146,93,240,203,85,22,47,64,59,152,75,20,235,27,17,66,105,0,172,3,218,116,211,176,80,145,91,208,28,43,180,123,12,87,43,140,213,8,199,45,22,34,44,212,119,229,240,126,233,100,82,75,71,193,27,108,230,25,204,43,187,38,139,215,58,250,248,12,129,156,156,53,218,188,120,38,195,127,181,116,67,0,53,76,92,104,10,207,183,2,201,154,181,237,205,31,117,33,157,21,102,59,104,123,210,233,44,52,243,72,16,114,181,88,94,22,145,129,99,46,142,218,247,48,143,73,239,236,233,73,109,30,170,136,14,65,140,251,66,129,141,74,67,38,228,202,59,110,143,37,56,128,163,22,170,238,124,102,151,213,43,198,193,100,17,40,225,165,101,56,85,202,93,60,125,90,237,128,4,143,148,101,86,46,212,228,211,132,223,180,36,94,56,36,148,98,89,183,88,239,49,81,193,92,133,208,68,44,45,69,232,135,1,76,205,174,30,55,48,10,97,180,187,196,65,185,221,42,131,87,226,162,220,12,109,162,115,46,193,172,48,9,45,52,252,249,201,179,89,35,247,148,6,71,213,237,150,45,106,245,212,162,147,88,36,77,104,237,119,89,147,198,42,242,202,77,106,201,86,109,13,93,105,226,108,202,126,160,12,100,116,198,149,100,122,101,138,115,112,2,75,18,212,214,77,151,4,87,139,60,212,70,176,75,109,53,138,60,237,70,98,33,30,119,166,206,193,161,166,64,221,60,193,99,104,85,116,24,105,227,62,130,198,131,65,229,101,1,97,203,194,83,124,52,110,202,87,95,149,112,232,179,7,232,50,152,7,243,192,108,110,118,155,243,122,133,238,200,139,106,225,5,111,128,167,249,80,253,7,72,228,53,175,155,186,13,242,44,15,37,100,73,30,228,192,150,243,181,112,238,119,246,248,254,203,61,190,177,225,228,145,133,34,236,160,41,8,2,62,232,237,115,117,186,246,19,165,97,168,114,73,52,247,240,7,228,48,7,119,0,222,176,40,194,209,132,66,169,31,32,62,227,86,83,212,176,52,179,240,157,202,28,40,32,176,228,50,98,109,180,80,90,41,7,206,108,191,158,141,5,82,1,211,75,154,210,218,100,174,7,188,181,88,84,237,53,21,84,180,46,221,60,40,186,158,11,179,160,153,191,130,122,172,204,47,162,82,42,52,150,175,63,67,41,72,128,4,119,18,116,65,128,131,112,141,111,142,167,179,236,78,242,12,62,139,97,140,62,68,175,227,225,60,197,91,89,249,67,244,19,56,40,120,15,252,137,231,210,222,75,88,187,77,65,17,192,106,31,205,151,220,229,171,156,105,104,153,131,223,123,120,105,30,38,188,246,7,37,35,96,195,224,26,54,169,37,51,62,220,56,116,13,83,82,189,80,11,96,74,197,83,227,252,218,9,140,150,179,148,81,228,178,136,105,95,213,94,238,73,35,99,189,88,0,209,115,196,34,10,246,40,133,83,220,82,218,167,124,0,205,234,58,28,174,193,136,143,35,57,120,7,163,81,101,56,178,90,244,25,141,249,218,67,189,96,253,13,137,127,238,3,233,132,139,230,24,237,162,28,230,47,226,204,6,219,226,98,64,51,199,166,113,146,145,61,219,85,177,226,70,30,254,127,143,105,79,70,127,9,142,85,11,39,114,121,103,79,253,250,121,114,45,55,151,37,164,56,87,203,8,28,222,118,75,185,9,39,0,174,173,90,104,88,178,144,44,242,154,162,111,221,198,209,80,113,231,255,107,119,110,47,120,107,124,208,122,221,105,189,188,188,223,116,159,45,126,187,80,151,59,11,231,135,182,243,202,206,33,132,174,58,251,24,191,20,251,254,238,206,206,246,206,43,187,180,38,129,121,15,232,2,116,43,143,101,82,230,0,183,1,209,30,82,204,104,210,59,137,58,183,29,60,74,29,55,8,117,110,95,195,63,11,135,203,249,30,109,44,204,20,13,63,191,42,205,208,61,25,136,88,223,159,231,62,89,196,175,193,203,186,110,101,124,144,74,215,139,182,147,158,227,45,120,134,80,67,153,37,123,234,152,191,198,53,246,136,124,189,124,38,201,156,49,99,154,173,35,43,241,171,154,15,10,189,162,109,32,60,189,249,195,52,18,176,115,116,225,84,227,70,115,181,5,246,134,86,63,29,157,230,77,173,99,27,208,242,28,124,66,217,156,49,49,176,49,181,94,90,194,152,225,110,141,71,145,174,52,4,211,4,207,89,2,197,174,242,230,148,51,171,176,151,237,91,197,9,132,141,249,93,193,152,130,217,3,140,243,193,123,122,46,149,58,43,190,52,129,41,140,28,209,35,39,215,229,133,219,13,117,40,27,44,239,28,46,77,66,43,47,25,156,63,220,89,131,153,85,21,140,138,179,201,21,133,241,178,133,50,65,182,139,183,52,208,74,146,184,188,240,182,221,166,52,31,31,4,2,186,102,175,100,87,146,49,203,114,90,250,172,204,76,185,99,75,211,134,152,142,90,0,97,171,123,119,154,147,65,16,64,169,59,122,20,200,218,111,235,187,133,6,95,118,13,210,206,216,201,244,187,0,55,135,160,216,155,243,29,224,195,251,202,174,193,28,208,198,208,145,92,36,129,1,215,43,242,152,169,163,179,10,238,23,78,183,156,51,74,167,135,54,103,227,86,49,195,132,92,115,244,97,114,240,133,156,188,121,252,197,105,156,123,141,83,166,54,195,229,28,174,123,117,105,139,14,78,103,198,249,233,134,71,163,214,83,77,40,74,215,228,29,235,28,138,98,143,78,228,84,75,210,249,96,26,100,165,161,162,40,111,163,223,89,207,255,241,38,60,173,120,121,78,61,155,8,3,16,250,40,226,204,175,66,32,146,0,220,131,127,10,153,86,9,94,9,140,244,3,41,11,226,66,174,58,93,230,235,150,149,196,76,238,188,226,222,108,158,78,114,213,218,205,223,241,47,64,11,203,167,151,198,83,245,136,178,24,74,71,98,116,47,46,23,180,196,237,1,199,32,5,239,235,147,21,235,160,106,255,87,36,175,100,24,236,48,246,20,232,166,37,115,80,232,11,126,109,11,131,12,150,178,144,26,34,4,200,226,205,131,173,218,110,26,179,38,19,108,41,159,46,5,197,248,14,196,210,85,90,168,182,31,144,45,218,28,115,54,236,86,58,203,143,214,218,130,43,244,215,179,56,70,65,105,223,211,145,197,120,4,113,215,194,0,181,75,159,24,168,120,207,185,148,183,228,230,2,30,128,40,233,74,127,125,129,174,187,138,92,72,75,80,71,195,158,168,45,226,165,208,85,227,218,184,83,74,185,182,27,2,30,42,202,241,231,62,194,185,4,70,197,75,175,195,83,75,131,41,54,149,1,140,203,178,146,46,96,254,102,79,159,174,149,118,53,61,125,90,218,239,215,224,7,254,121,79,155,46,206,239,70,203,179,48,66,7,104,153,202,143,38,169,227,73,193,172,48,221,23,205,135,229,199,234,21,249,13,43,40,82,251,10,164,250,146,55,86,165,174,218,247,90,54,25,135,113,24,242,89,154,63,230,201,21,126,30,80,127,199,41,47,238,149,61,203,164,133,103,108,89,61,185,196,138,8,4,87,36,171,148,199,196,74,213,105,102,66,115,86,239,187,20,231,59,27,24,88,198,101,28,233,187,83,250,43,133,109,171,252,97,67,174,236,181,50,121,37,130,172,142,112,205,87,192,114,248,161,47,235,25,70,121,46,206,203,148,149,98,175,76,214,170,124,238,105,89,144,91,236,149,166,41,70,44,189,19,186,124,196,107,167,101,57,18,148,146,132,189,242,130,96,78,191,162,51,221,90,30,226,52,122,167,19,186,173,106,141,102,62,202,223,103,96,37,25,44,136,249,30,45,48,2,102,241,108,62,243,229,129,14,242,161,184,5,88,70,2,80,147,167,58,244,228,145,227,165,161,31,194,180,203,140,113,231,230,168,148,190,167,86,29,20,130,189,37,191,187,178,210,200,148,94,208,195,115,32,111,75,4,147,248,165,2,68,2,199,35,103,115,112,130,235,64,206,197,250,56,210,10,140,90,219,81,222,166,169,52,86,0,79,87,87,128,145,98,161,3,72,148,106,89,194,64,121,151,171,246,208,202,83,112,84,79,178,125,246,90,61,94,210,15,46,152,215,182,154,53,118,35,107,182,170,19,225,39,122,92,180,142,46,171,121,37,119,84,201,191,48,7,151,136,72,162,108,238,211,154,117,112,211,40,149,22,169,142,74,245,224,183,29,171,34,55,108,165,211,214,54,242,84,225,79,150,245,92,115,91,86,79,6,104,216,123,48,27,181,159,169,157,166,226,141,188,17,82,194,120,114,147,128,14,14,41,156,195,168,41,207,243,136,237,165,199,83,66,191,124,105,226,183,50,18,39,163,42,252,50,233,82,67,127,50,42,79,67,35,113,180,152,139,203,144,195,198,75,120,29,211,54,221,201,124,128,155,116,107,72,213,65,126,86,70,196,204,237,164,110,74,27,138,37,119,17,110,195,97,230,38,87,131,27,252,211,199,155,241,60,235,188,120,73,63,47,55,203,116,80,241,96,171,71,182,67,142,204,242,68,2,253,194,146,84,130,71,214,251,245,54,197,222,242,157,137,122,225,228,177,109,137,155,32,112,228,122,174,159,47,200,247,216,102,142,194,87,37,30,124,19,4,91,208,223,214,31,216,31,176,48,219,254,3,251,3,254,99,207,86,236,143,149,184,179,224,69,201,122,223,3,154,29,128,102,231,79,3,205,46,64,179,251,167,129,230,57,64,243,252,79,3,205,11,128,230,197,31,200,167,29,232,239,32,12,243,30,75,58,242,1,217,106,136,65,10,241,245,62,138,105,12,138,7,227,14,77,146,208,48,13,151,236,94,86,231,81,214,44,196,178,55,210,108,47,42,120,122,232,4,23,74,229,1,27,80,217,254,75,13,65,18,215,18,49,52,215,76,138,161,118,40,47,130,225,97,105,37,235,206,172,14,58,164,92,251,240,240,124,105,101,165,116,114,115,48,151,248,229,222,54,30,105,163,246,194,210,202,57,227,26,245,229,233,110,172,205,126,122,241,224,123,164,14,43,239,189,220,196,247,182,170,38,216,67,76,181,204,232,216,220,122,64,133,23,83,175,164,172,225,215,205,81,90,181,143,201,78,239,205,28,216,6,126,191,22,198,221,138,75,91,164,141,45,45,80,249,100,205,94,106,61,151,180,96,89,245,83,35,229,18,144,151,147,203,48,107,190,142,74,103,121,70,242,55,19,75,202,43,29,0,160,188,53,102,100,172,177,90,234,179,4,93,214,196,111,11,162,196,42,63,227,183,96,207,116,42,79,181,157,3,207,191,141,78,138,155,26,77,192,175,32,25,165,26,178,243,34,239,249,155,41,103,60,173,125,167,122,101,194,154,9,216,255,26,202,126,221,244,6,90,20,105,219,223,68,26,106,102,53,228,101,22,248,247,70,251,171,152,129,114,11,127,7,162,133,186,202,147,39,11,231,33,40,155,3,121,118,39,43,237,138,200,251,49,232,83,94,255,85,122,183,238,32,72,137,222,60,119,152,252,86,237,82,201,156,203,27,108,226,161,56,99,221,230,50,243,68,101,243,234,9,173,182,247,105,54,88,189,95,241,167,80,236,82,249,16,113,87,237,17,93,211,135,58,139,104,87,139,52,10,222,227,117,165,183,149,49,147,59,96,30,234,106,198,131,228,241,48,221,60,85,97,186,83,168,254,141,192,168,67,99,30,128,101,30,173,2,141,121,116,12,251,68,175,84,7,3,45,129,25,252,206,30,230,227,175,225,47,197,79,198,43,213,15,151,63,18,213,174,90,159,120,173,206,26,126,104,120,48,143,60,158,167,138,25,74,42,188,137,56,4,79,83,228,217,124,145,214,146,44,101,194,42,219,224,247,131,206,232,92,147,113,112,91,227,102,113,155,173,10,191,102,181,138,241,108,10,41,221,75,69,27,20,179,240,59,136,141,63,206,157,192,65,120,56,136,252,136,3,193,202,41,191,101,59,248,219,136,210,20,150,250,95,226,127,121,196,52,126,89,161,175,208,251,158,51,224,12,27,254,142,83,224,1,232,137,62,127,4,247,215,220,32,124,155,66,130,141,235,220,6,83,240,144,210,59,244,146,200,40,224,97,124,85,19,147,60,108,45,47,105,140,101,203,162,149,150,254,228,198,4,73,69,240,75,166,65,254,190,213,123,74,199,8,239,21,100,153,108,149,123,80,131,170,63,194,41,183,11,160,9,180,213,60,9,116,26,202,163,70,17,51,13,35,204,61,104,160,167,204,73,232,237,103,116,240,121,145,54,131,16,237,103,242,235,240,89,130,151,121,212,250,104,191,13,119,248,4,191,38,119,26,39,89,254,224,52,137,49,150,18,50,181,105,58,47,40,86,16,171,58,94,131,131,251,47,136,21,17,198,202,102,140,149,245,188,244,170,177,63,60,123,13,175,36,2,72,175,38,228,245,150,13,172,138,117,240,23,113,135,95,164,203,99,206,100,177,82,240,52,26,164,179,189,10,231,86,22,95,254,122,44,91,44,171,174,196,171,117,42,173,98,209,19,227,202,5,67,218,2,98,82,182,18,223,147,137,53,203,204,201,124,59,223,153,172,246,181,131,156,135,156,240,228,77,70,127,91,55,60,161,45,234,242,110,16,198,195,47,42,193,172,180,253,104,165,161,168,189,166,246,59,53,12,199,179,222,185,172,200,212,65,208,204,166,15,139,96,210,174,254,138,158,3,163,242,204,96,198,202,137,209,203,144,44,22,77,171,107,148,127,61,254,173,45,186,126,149,200,109,224,3,139,236,247,65,239,32,196,188,60,150,241,47,130,113,150,135,0,219,70,14,131,58,89,161,224,101,143,210,207,122,114,225,22,143,159,191,139,231,152,238,89,100,46,176,129,24,227,167,92,230,179,171,132,142,34,242,24,160,216,59,139,167,66,30,85,47,11,240,243,39,242,195,98,242,180,122,185,39,52,117,213,23,57,240,203,33,195,56,73,230,51,249,129,53,202,205,161,77,129,30,59,25,203,79,196,76,40,247,10,94,33,189,45,219,113,129,179,192,31,70,160,213,123,146,106,174,226,186,52,147,159,153,17,108,9,10,30,57,54,171,76,39,34,227,145,162,80,222,17,27,4,17,199,51,150,244,23,31,69,65,89,125,248,130,113,240,194,227,71,46,128,206,13,178,55,243,1,211,15,24,110,166,69,74,123,172,88,249,231,44,50,142,248,24,128,183,141,153,103,244,141,2,121,180,135,85,203,18,176,152,100,60,137,49,113,196,59,100,133,116,174,41,132,152,220,233,239,188,73,162,210,247,49,56,57,189,51,250,112,4,54,72,4,164,79,37,175,225,80,231,172,42,63,33,20,68,88,153,103,193,128,62,159,163,206,234,28,210,215,63,84,206,32,163,99,26,26,70,22,200,70,220,65,224,208,183,152,169,201,79,103,63,153,227,84,18,190,109,61,18,22,147,9,149,120,124,91,10,242,86,68,67,57,71,101,186,52,79,50,146,172,45,156,156,229,57,99,166,117,85,22,111,140,34,165,244,77,179,83,203,242,89,18,208,217,30,189,159,232,136,18,86,146,255,148,113,166,130,57,242,58,205,238,164,128,162,88,113,55,138,35,81,95,91,95,49,37,25,147,220,48,29,11,244,149,186,250,54,20,180,58,2,241,67,252,157,143,105,163,46,91,9,3,37,196,77,117,86,19,96,99,96,132,71,165,106,197,95,88,34,95,15,81,246,26,193,139,7,116,166,153,131,243,215,86,35,171,106,15,164,72,245,164,26,253,222,36,33,229,174,54,199,21,86,180,169,200,171,199,55,85,169,93,62,230,198,162,6,223,210,179,122,123,58,32,44,3,159,15,183,164,19,83,36,203,229,77,213,23,50,243,211,160,36,85,225,10,61,10,121,116,82,222,135,124,237,163,20,188,236,136,232,183,90,83,249,215,67,251,60,91,210,220,251,152,82,181,84,123,179,68,60,212,158,26,26,250,86,134,204,250,225,75,170,227,241,12,190,60,38,201,120,31,183,0,224,249,72,86,239,151,0,20,5,48,154,212,42,229,68,200,198,86,145,200,229,179,152,10,173,87,206,4,123,220,42,253,223,158,228,205,9,103,127,189,201,46,51,232,216,83,246,81,89,60,95,235,4,237,79,182,243,121,39,63,26,92,105,218,104,112,187,247,53,182,227,114,93,89,109,184,204,153,75,1,106,64,113,187,106,19,20,96,253,127,155,224,251,217,4,223,213,20,248,211,201,138,166,36,224,191,158,164,144,137,214,121,110,243,227,210,161,136,148,75,210,84,150,46,31,252,166,1,49,209,148,25,167,187,84,98,186,232,160,193,36,148,147,154,39,15,44,205,125,99,7,228,42,150,206,63,7,182,64,239,17,191,205,199,228,118,166,166,5,175,63,13,119,182,85,4,16,21,122,239,127,0,23,97,106,76,237,161,0,0}; \ No newline at end of file +#define index_html_gz_len 11390 +static const char index_html_gz[] PROGMEM = {31,139,8,0,0,0,0,0,0,19,237,125,107,119,219,56,146,232,247,251,43,16,166,39,150,218,20,37,219,177,147,200,150,178,110,219,233,120,55,15,223,216,153,222,61,30,95,29,72,130,44,38,20,169,33,169,56,94,183,254,251,173,7,64,130,15,217,74,38,51,219,167,239,77,207,88,36,1,2,85,133,66,189,80,0,15,30,141,163,81,122,59,87,98,154,206,130,254,1,254,21,129,12,175,123,142,10,29,184,87,114,220,63,152,169,84,138,209,84,198,137,74,123,206,34,157,180,158,67,89,234,167,129,234,191,245,223,248,215,211,84,188,94,12,15,218,252,232,32,240,195,207,34,86,65,207,73,210,219,64,37,83,165,82,71,76,99,53,233,57,211,52,157,39,221,118,123,38,191,142,198,161,55,140,162,52,73,99,57,199,155,81,52,107,103,15,218,59,222,142,247,172,61,74,146,252,153,55,243,161,86,146,56,186,143,98,147,215,126,138,173,192,207,116,49,244,252,40,127,175,149,70,215,215,129,106,111,123,240,95,177,73,93,148,181,92,129,187,182,43,232,231,83,226,141,130,104,49,158,4,50,86,4,186,252,36,191,182,3,127,104,183,158,4,254,88,197,237,23,222,51,175,83,234,152,139,126,108,199,137,10,212,40,245,255,91,121,159,146,118,199,219,218,246,246,168,215,252,121,214,255,206,63,13,101,234,171,189,133,189,63,45,227,76,101,247,245,76,188,22,202,153,234,57,95,124,117,51,143,98,96,157,81,20,166,42,4,222,187,241,199,233,180,55,86,95,252,145,106,209,141,235,135,126,234,203,160,149,140,100,160,122,91,208,196,163,86,235,210,159,136,32,21,167,39,226,197,85,255,127,9,248,119,144,140,98,127,158,138,36,30,173,141,19,206,134,221,100,234,127,1,94,124,230,237,228,247,64,93,232,167,205,77,98,251,7,143,46,85,56,246,39,87,173,86,255,128,240,233,123,56,119,84,220,138,163,155,187,97,20,227,229,48,74,211,104,214,221,154,127,21,73,4,163,47,30,143,70,163,101,32,135,42,184,27,251,201,60,144,183,221,97,16,141,62,47,189,88,142,253,168,21,205,83,63,10,239,230,114,60,246,195,235,110,71,236,206,191,238,143,22,113,18,197,221,121,228,3,81,226,37,194,60,147,225,184,53,92,64,235,97,114,23,248,73,218,34,24,186,97,20,170,253,153,140,175,253,176,219,217,207,154,169,188,35,2,63,3,192,15,97,240,85,139,224,208,239,182,98,156,226,221,45,53,219,143,190,168,120,18,68,55,93,185,72,163,165,55,137,226,89,11,70,38,190,189,51,221,136,142,216,238,0,134,29,187,84,240,53,142,99,28,5,119,52,114,221,237,142,154,21,42,21,41,97,3,194,68,2,124,210,134,167,226,56,138,155,130,127,91,126,56,137,178,87,16,223,165,93,48,138,2,32,85,172,198,251,19,232,186,149,192,12,232,122,207,176,219,188,82,119,168,0,6,117,167,153,172,187,209,216,40,20,203,9,144,57,47,109,66,169,30,218,97,26,26,180,17,229,165,119,45,83,117,35,111,91,64,104,42,4,74,201,180,75,212,91,62,214,45,8,111,28,71,243,113,116,3,227,26,37,62,14,112,87,243,112,137,186,213,55,90,51,21,46,236,193,98,226,60,134,185,53,153,248,163,86,18,250,147,73,145,26,143,233,153,26,183,116,29,0,248,107,107,170,104,64,119,59,214,136,182,110,245,152,154,206,238,27,14,47,148,95,134,50,190,27,202,209,231,235,56,90,0,43,105,82,95,15,101,227,233,150,139,255,219,117,189,23,205,71,254,12,231,176,12,211,125,61,11,144,181,23,9,114,33,55,210,26,198,192,138,110,225,174,59,69,176,244,240,61,158,76,38,75,15,232,9,226,3,72,50,150,192,109,149,142,177,146,238,161,60,193,60,6,125,5,38,55,83,63,85,173,84,205,230,173,185,63,250,12,189,106,234,108,3,113,242,110,186,248,14,128,119,141,224,195,160,52,210,72,208,192,186,143,229,222,120,107,50,17,29,23,97,16,187,157,191,224,133,236,116,58,98,171,211,249,75,115,191,118,102,153,201,184,195,83,101,186,80,53,221,243,60,193,86,246,75,242,33,175,15,76,26,214,189,5,226,112,212,192,87,69,75,236,168,217,10,48,138,194,100,45,124,97,54,49,174,128,223,158,183,183,183,247,12,16,238,192,221,14,104,108,248,71,119,154,14,157,206,68,236,101,149,38,112,247,220,84,194,102,136,62,140,204,23,25,192,95,13,227,93,117,32,129,156,70,26,5,106,146,118,189,221,12,83,196,217,66,191,126,152,231,193,34,105,129,222,129,191,136,224,252,174,48,215,108,74,143,2,192,187,11,178,122,90,38,122,185,13,193,226,179,59,241,99,16,185,209,164,133,150,84,81,216,179,232,204,120,222,204,129,52,154,151,75,88,86,32,110,235,118,27,200,149,189,98,51,181,157,22,11,30,234,200,35,131,206,180,173,105,132,12,107,154,212,115,15,102,153,121,194,138,135,6,45,227,113,208,90,194,252,255,25,104,176,76,35,233,81,219,121,10,15,105,176,244,131,45,239,233,139,123,8,50,241,85,48,134,186,193,188,94,107,229,178,126,203,219,70,62,41,51,14,72,234,224,118,62,245,65,154,120,201,28,38,16,64,121,39,67,127,38,73,28,227,35,177,149,8,16,255,40,153,149,224,185,176,223,186,81,195,207,126,218,42,214,220,174,169,186,68,83,33,151,239,96,230,64,253,47,160,139,1,10,131,35,240,218,114,24,141,141,230,52,214,193,118,7,85,201,4,76,38,107,86,211,179,127,155,169,177,47,69,20,6,183,2,76,15,165,66,1,162,82,52,176,81,26,27,209,221,65,61,212,188,171,107,118,23,155,88,167,141,167,207,87,182,209,89,183,141,103,123,207,87,180,177,181,251,124,205,54,94,188,216,94,213,198,214,30,182,225,205,162,49,24,126,88,65,120,9,218,183,81,216,42,112,108,213,224,82,74,25,182,52,165,30,8,13,173,38,69,206,23,45,146,67,154,191,247,38,123,53,53,18,152,80,153,138,218,219,91,46,2,79,50,16,171,76,49,203,2,43,214,92,101,128,213,212,35,35,72,139,156,209,212,15,198,205,187,10,123,255,219,103,117,59,137,193,136,78,4,114,232,221,36,142,102,119,96,0,132,9,90,91,93,50,149,27,91,77,17,71,41,88,44,141,78,115,153,70,247,148,239,236,117,198,234,186,9,163,102,102,64,177,253,109,238,192,20,230,13,21,218,95,89,156,53,239,101,110,74,107,12,87,169,42,24,80,222,168,149,151,195,84,155,229,38,39,88,166,75,48,199,201,238,62,104,179,211,138,108,209,175,181,250,209,192,247,174,163,8,220,62,57,247,147,146,209,255,233,239,11,21,223,130,197,15,14,140,190,33,127,165,96,242,215,182,187,174,75,251,169,236,209,62,220,244,186,174,237,167,21,158,237,195,61,60,224,10,129,69,160,226,100,4,118,50,122,150,91,222,115,112,135,242,103,173,31,210,199,10,175,185,214,99,254,135,59,171,243,148,225,42,1,75,21,132,10,76,86,171,198,143,198,174,224,32,127,90,225,31,215,118,200,161,153,84,125,77,219,159,228,23,201,79,157,254,100,17,146,152,16,96,126,95,68,175,147,160,33,93,229,198,205,59,217,238,109,239,238,186,138,127,98,250,217,255,34,99,145,184,169,59,234,189,149,233,212,3,182,213,213,221,169,126,226,135,230,73,216,107,140,54,167,205,246,246,190,63,105,140,122,189,105,51,233,165,189,206,190,10,18,117,135,13,13,123,163,214,116,63,185,1,6,157,54,210,94,216,247,118,95,14,219,141,237,22,60,110,118,225,10,95,119,71,205,187,145,76,148,144,221,164,215,80,173,184,217,30,110,54,212,65,252,114,175,219,105,238,15,99,37,193,20,197,10,10,43,196,45,137,21,182,237,130,24,11,100,75,97,193,211,101,210,238,237,45,99,149,46,226,240,110,218,77,220,164,155,186,224,30,46,151,25,37,62,252,250,75,26,189,62,255,171,161,196,86,175,215,3,113,177,0,15,42,77,188,64,133,215,233,244,201,147,134,234,73,239,218,141,225,239,208,149,240,55,110,26,242,84,136,51,170,16,103,218,3,17,12,36,234,64,219,233,203,78,119,218,78,221,97,47,109,35,145,13,69,52,226,35,0,191,99,227,131,148,0,66,108,78,127,206,232,224,34,86,63,79,203,228,0,106,108,110,255,60,173,41,69,154,0,73,54,159,102,165,69,154,132,238,151,238,112,185,92,151,139,126,106,24,234,53,154,119,63,53,198,209,136,168,213,244,224,129,51,154,194,75,202,113,29,80,61,1,252,90,85,145,96,170,247,83,35,157,250,73,19,8,167,60,48,230,27,77,47,86,160,207,70,170,209,254,219,223,218,215,174,211,118,172,71,222,207,127,107,183,93,199,105,238,43,47,5,249,126,173,226,134,131,45,243,12,112,220,203,244,170,185,108,186,54,24,128,248,248,182,8,163,134,134,65,180,95,207,106,41,55,101,8,165,129,208,155,195,228,4,38,104,56,224,24,206,23,41,219,186,208,6,88,112,99,104,17,233,226,52,93,191,151,238,203,140,81,36,225,228,3,72,248,31,241,200,199,119,167,23,131,179,195,15,135,111,207,123,119,192,21,111,125,112,105,18,48,112,118,92,224,26,125,183,243,172,131,119,191,144,10,11,85,146,128,33,182,187,116,63,158,14,46,14,127,57,239,93,222,165,242,186,235,164,114,8,86,207,196,7,184,99,112,182,198,193,109,215,249,13,239,151,110,94,33,129,161,157,219,53,206,233,129,93,37,80,99,187,194,155,147,227,66,49,5,149,236,10,31,232,129,93,101,246,247,52,181,107,188,253,223,23,23,206,242,10,1,126,117,122,242,230,56,3,89,142,1,229,193,34,81,49,6,235,236,87,14,177,68,228,37,104,167,119,157,143,250,94,128,230,23,1,104,38,176,131,192,106,6,175,18,7,69,128,109,48,151,200,95,232,204,116,29,144,134,80,14,119,114,104,81,199,0,202,125,207,101,146,220,128,157,103,247,125,150,61,227,94,205,253,143,232,117,26,37,105,25,215,215,217,51,238,239,92,5,147,22,48,121,20,167,224,222,154,55,4,244,151,192,27,2,21,203,181,0,201,48,21,199,71,175,207,68,172,192,190,72,210,245,250,199,155,1,232,167,212,31,13,252,34,35,208,67,113,122,38,14,199,227,24,152,44,3,39,43,144,92,32,26,96,243,124,81,98,8,34,224,51,130,5,195,36,142,95,31,157,53,191,7,134,65,168,210,153,76,62,215,195,242,206,20,50,44,250,214,116,74,68,200,42,127,87,239,58,218,86,223,251,175,92,88,166,136,69,10,13,136,76,132,110,72,220,76,209,13,201,161,18,62,218,183,202,31,249,19,156,88,235,128,56,82,3,48,136,109,144,142,78,68,91,156,253,199,133,160,231,154,45,97,130,128,142,58,57,63,123,190,189,183,135,96,48,135,110,28,157,108,136,6,94,189,251,240,106,251,233,155,206,150,160,184,204,4,100,102,83,96,5,104,72,215,216,56,123,3,126,208,179,246,155,139,231,47,58,157,13,171,226,74,72,147,130,192,24,37,97,5,214,243,119,235,129,121,254,110,99,205,94,128,212,42,45,247,243,225,228,252,100,61,130,80,205,117,251,2,241,87,238,9,68,96,185,31,61,238,216,60,150,34,63,45,18,161,189,47,209,232,244,224,82,14,161,173,230,190,8,213,53,57,238,64,221,47,96,235,162,191,227,95,135,50,16,141,88,97,12,29,39,117,107,155,218,66,39,45,146,32,106,160,209,117,135,96,46,71,159,129,58,32,48,148,76,147,162,32,195,18,145,149,48,248,23,83,37,194,197,108,168,160,187,137,72,125,116,192,48,46,71,181,196,135,87,130,27,76,80,218,164,88,50,92,4,195,100,37,48,113,65,252,23,129,25,204,85,60,8,162,104,190,26,42,1,85,4,87,209,83,60,3,205,212,48,130,207,199,121,149,64,239,129,18,215,145,39,196,107,208,135,80,149,162,126,137,152,41,25,138,25,56,18,32,150,65,25,95,79,65,45,187,24,230,18,1,206,212,217,34,0,183,30,132,7,52,224,173,137,13,90,229,26,151,1,204,138,52,138,11,114,251,226,226,204,144,205,148,50,14,111,177,175,121,224,143,120,220,185,16,121,179,72,30,26,114,45,190,49,250,131,241,123,20,249,195,91,64,65,9,106,255,240,236,212,19,31,143,233,66,0,208,208,102,16,220,194,91,35,5,77,3,203,45,184,31,101,134,205,21,73,196,100,48,189,36,211,104,17,64,171,42,159,18,216,244,154,106,114,145,70,0,47,48,120,156,226,112,250,81,65,87,30,66,113,75,23,11,83,204,68,192,34,140,112,25,128,185,14,34,198,75,111,66,193,108,184,181,88,17,131,134,41,69,3,20,8,75,95,141,1,113,152,99,29,130,216,204,167,53,39,5,84,31,97,112,246,118,64,139,127,22,196,199,166,68,112,137,182,44,128,194,120,143,204,134,1,23,144,225,186,87,83,89,79,138,40,244,196,177,154,72,24,97,226,76,196,39,65,245,76,111,19,129,97,248,204,130,54,99,10,99,242,244,249,243,23,47,12,62,240,154,70,103,189,49,64,123,106,0,166,15,0,82,54,171,132,121,204,104,28,3,197,81,10,198,182,186,6,210,82,213,97,28,125,6,207,87,188,167,5,65,26,21,38,245,45,204,43,2,159,244,105,67,125,149,179,121,0,186,98,118,139,239,233,215,70,24,3,123,254,252,233,74,144,201,234,43,128,156,70,192,174,96,98,165,160,84,194,10,228,84,42,178,82,99,107,209,45,17,63,175,149,88,195,130,3,112,194,16,118,225,25,80,57,105,119,153,206,3,127,156,93,34,144,237,46,89,229,240,216,19,231,74,137,15,39,135,199,111,79,168,237,201,34,78,81,118,140,85,42,253,96,181,116,171,34,181,152,143,97,182,61,128,27,87,186,31,69,64,105,190,24,2,86,83,97,189,147,120,226,76,179,90,58,5,193,34,105,34,211,100,135,169,27,71,51,17,105,192,53,103,97,196,115,94,126,131,68,55,213,38,19,85,79,184,27,63,8,112,34,2,239,162,48,213,29,130,96,64,131,22,95,249,6,50,160,198,123,136,10,84,231,91,198,217,166,137,121,217,19,191,177,69,197,171,9,236,66,38,92,236,210,244,155,44,0,173,207,33,174,54,242,75,168,214,224,57,191,64,72,131,236,211,237,2,21,141,225,94,2,108,125,14,168,241,87,120,4,161,64,148,253,21,97,140,119,240,28,4,91,14,133,137,187,118,183,117,174,10,181,52,95,229,175,100,157,126,119,159,163,0,151,237,6,108,222,240,104,87,186,63,162,58,100,240,130,9,116,193,117,24,146,163,40,12,57,164,110,44,36,48,54,18,137,227,247,192,176,128,118,191,192,27,63,28,5,139,49,212,127,243,219,5,177,250,208,135,137,11,165,247,206,231,213,250,189,128,98,226,163,20,25,84,49,45,152,179,5,244,222,26,248,223,70,227,108,152,79,1,61,106,10,244,238,24,152,146,22,36,72,49,80,247,137,216,24,49,33,212,120,131,144,216,32,189,146,61,170,208,2,240,131,54,25,23,160,12,183,10,147,85,10,57,140,22,172,68,209,148,4,194,186,150,164,119,133,74,129,114,166,57,77,187,113,70,13,206,4,25,232,101,0,199,229,251,164,123,231,164,241,66,57,224,249,16,22,142,235,76,100,144,224,131,99,13,2,144,172,158,132,211,104,166,6,192,111,62,198,60,211,129,165,118,99,53,241,191,22,221,220,153,58,52,53,153,31,115,93,124,166,171,107,130,78,128,85,193,120,35,76,84,136,154,146,92,147,235,152,86,204,88,79,21,218,219,72,184,197,92,97,155,224,141,12,252,244,22,153,11,20,94,116,3,186,26,5,41,60,148,9,219,189,67,180,71,82,26,9,33,109,147,101,61,30,34,131,113,144,249,77,164,119,42,209,145,220,175,18,92,206,104,110,123,79,197,175,175,255,91,80,27,52,202,1,104,103,100,30,150,114,60,31,252,137,184,141,22,36,224,240,98,3,196,123,24,161,169,129,82,27,76,94,227,229,61,122,112,152,67,172,217,117,232,199,113,217,231,3,113,97,187,128,246,64,23,109,225,120,178,253,20,140,169,27,180,232,193,114,11,108,36,169,69,113,134,133,226,13,23,106,81,68,143,168,62,77,211,80,195,250,32,168,111,79,223,129,120,65,159,235,205,251,223,192,3,139,110,28,247,245,233,175,175,129,141,64,229,59,238,219,195,255,132,114,249,245,1,120,217,102,24,32,57,195,58,144,223,176,77,113,100,202,25,234,223,166,254,104,42,244,75,73,201,36,204,36,24,240,33,206,67,77,205,7,240,33,44,8,159,183,167,199,120,53,46,224,115,63,22,6,146,42,252,231,232,23,29,101,197,171,192,39,247,201,6,28,17,201,128,7,105,243,145,152,105,162,112,180,178,23,193,56,84,227,4,204,4,122,63,89,41,70,96,170,166,40,230,186,119,51,246,123,84,247,81,103,249,143,227,174,7,175,198,177,213,195,86,114,108,79,195,81,172,36,97,146,106,221,129,247,56,205,1,85,57,139,22,32,119,180,203,139,200,193,29,119,65,184,3,69,180,25,133,198,34,57,2,182,165,158,87,205,236,127,140,236,236,172,86,53,5,19,158,205,165,73,176,72,166,44,44,192,105,45,199,156,192,146,193,114,145,151,107,111,18,60,195,217,98,86,240,148,2,0,135,242,152,208,124,75,111,112,233,155,94,38,75,78,91,78,240,68,38,211,122,108,64,212,200,91,210,69,254,140,86,209,83,5,98,103,142,58,37,73,75,45,172,233,114,89,102,97,140,127,2,127,230,87,194,192,186,105,172,32,116,133,111,66,210,182,148,177,18,198,38,116,155,141,177,229,150,237,118,58,171,227,39,5,1,94,112,201,7,24,58,72,83,48,10,224,66,129,227,28,140,87,134,46,132,169,43,172,186,153,221,131,41,138,137,152,130,204,158,23,227,29,82,7,40,240,77,84,244,103,118,180,133,20,27,133,43,136,73,13,214,192,191,104,201,203,144,25,155,2,30,162,1,198,164,77,163,38,171,203,145,196,192,84,169,83,214,115,89,183,2,83,243,160,239,183,28,45,41,182,75,173,192,84,49,216,45,230,80,211,118,121,183,59,157,217,119,197,131,114,234,2,178,152,213,242,5,84,243,26,244,45,212,254,102,10,23,163,68,54,121,170,116,1,89,135,115,130,50,23,39,18,38,124,92,100,171,142,43,102,242,43,49,42,19,107,171,211,129,103,29,51,175,146,213,76,119,31,93,102,204,252,171,73,145,85,168,193,126,34,99,131,1,206,254,145,68,203,145,37,31,203,248,82,64,77,229,254,98,1,183,157,117,97,103,167,90,75,52,204,162,42,200,230,95,201,235,226,41,105,74,179,117,13,48,179,192,244,39,253,196,101,86,112,202,152,171,232,36,89,162,194,76,118,28,151,15,39,231,23,232,192,206,65,175,40,14,159,229,2,192,64,95,7,94,253,212,103,203,114,144,89,125,3,52,193,6,188,232,74,4,200,177,58,97,35,52,171,74,214,154,176,170,50,138,175,0,162,15,191,254,242,219,111,28,52,21,13,182,210,224,209,230,209,209,5,198,101,94,125,188,232,60,127,209,116,181,89,155,88,77,102,173,101,243,30,59,65,61,38,40,19,137,140,216,201,4,104,152,121,193,232,51,169,25,136,109,112,78,128,235,145,70,9,94,106,51,25,29,103,10,23,220,128,144,16,62,200,23,34,54,154,143,224,32,126,94,219,47,96,236,109,191,64,135,175,86,235,110,53,102,106,210,114,11,200,167,137,127,93,14,169,19,9,199,11,228,53,129,213,132,169,198,180,204,170,16,26,86,220,144,84,187,56,28,141,80,78,158,97,210,169,174,39,253,148,148,127,164,91,66,146,208,10,168,198,211,0,101,241,3,251,54,117,48,79,216,241,169,131,153,0,34,136,185,146,238,49,164,69,227,7,128,159,202,164,250,150,9,36,82,155,33,12,190,53,56,235,2,29,17,23,148,216,182,8,134,85,101,45,18,39,11,162,49,198,87,110,69,188,160,12,199,111,5,139,69,77,45,76,89,60,60,89,7,30,180,65,113,116,41,100,142,241,48,188,201,222,255,30,160,128,45,23,97,1,180,87,104,238,136,17,27,138,21,232,222,149,23,77,0,62,132,152,20,38,89,74,12,183,145,174,168,135,104,162,90,100,171,136,86,130,239,202,253,245,195,251,143,103,131,243,139,195,139,147,193,127,156,252,215,121,239,210,209,66,205,49,33,9,103,152,173,255,195,141,246,193,156,233,130,234,100,147,30,110,40,155,16,126,153,18,206,103,21,124,241,179,231,3,148,23,216,24,200,39,77,43,40,152,205,23,160,23,6,230,77,69,82,6,46,178,184,42,92,155,88,106,254,152,125,89,39,154,234,23,175,92,32,199,224,237,251,227,19,132,255,253,100,2,133,231,232,116,115,18,25,220,189,2,157,154,223,81,217,48,192,117,104,46,49,215,1,37,165,195,213,251,16,26,253,120,124,54,56,251,240,254,226,253,209,251,55,131,191,158,124,56,63,125,255,14,58,216,117,247,174,220,227,147,87,135,31,223,92,12,242,58,89,149,222,174,155,101,95,185,218,225,63,207,30,80,34,38,12,69,239,209,150,27,68,18,89,235,92,251,49,248,136,180,14,220,144,54,59,29,219,143,14,177,41,120,128,201,76,142,243,168,23,68,35,162,188,103,86,234,57,85,228,70,13,207,35,100,132,94,168,110,196,111,230,174,225,220,96,158,151,179,89,121,109,211,233,62,223,114,154,251,217,139,94,20,106,159,173,151,103,162,52,239,160,91,3,60,247,132,201,50,24,28,218,255,169,225,148,119,106,56,77,111,142,106,31,147,82,14,224,170,239,108,166,155,206,65,155,46,155,203,229,146,26,136,94,171,175,133,62,56,3,200,233,124,117,54,149,151,70,231,196,181,141,173,189,38,220,124,156,131,24,57,2,106,54,154,75,38,138,50,84,178,155,168,80,176,147,15,135,7,158,195,95,209,126,106,0,228,196,75,167,227,38,250,145,186,50,60,190,230,43,122,138,177,182,172,230,5,48,93,179,110,124,98,53,65,51,156,158,144,59,133,240,229,109,22,128,251,169,177,241,88,247,32,40,127,231,18,9,200,251,7,122,206,198,166,218,220,112,174,54,154,222,8,57,81,183,131,80,84,26,33,105,21,248,15,189,126,173,210,163,69,140,25,67,199,26,221,158,149,130,196,212,6,185,17,39,234,52,76,27,57,157,174,13,157,154,133,70,42,40,101,109,32,11,24,196,40,237,151,150,157,1,65,96,4,132,177,225,16,144,48,244,46,102,42,29,134,99,158,18,204,212,86,123,192,101,143,74,68,54,73,90,119,249,64,116,115,152,104,144,154,174,25,206,110,21,101,40,213,160,117,43,168,32,145,210,222,251,225,39,204,92,196,141,92,190,74,26,229,73,235,105,195,4,179,172,2,176,205,243,52,174,52,35,192,192,243,147,147,191,47,100,208,72,47,183,174,60,10,247,81,31,103,50,150,179,196,85,152,121,85,154,202,29,55,213,57,90,253,206,203,74,167,25,175,166,151,157,171,102,183,82,78,91,61,26,205,138,124,88,46,93,30,128,143,113,208,171,100,186,213,146,39,237,213,16,198,149,189,50,149,89,244,244,122,170,137,134,255,141,243,118,1,194,83,97,216,192,40,204,211,99,7,43,101,236,160,119,1,102,92,0,166,51,92,39,243,192,7,137,228,194,165,9,180,55,100,243,247,223,27,105,175,211,116,29,204,205,5,46,1,13,213,235,161,172,71,205,87,237,145,151,89,176,67,45,53,218,58,21,38,1,41,7,82,13,254,74,250,155,46,171,115,212,38,76,137,221,126,255,253,39,228,255,127,63,127,255,174,145,17,18,200,97,79,65,208,174,227,64,81,75,31,73,18,53,112,124,237,169,82,156,181,133,121,162,231,174,158,38,213,9,98,201,182,222,192,51,78,98,195,238,31,247,44,254,228,97,126,110,227,110,17,7,93,27,206,153,74,167,209,24,60,185,143,23,142,139,77,119,17,21,143,45,0,127,114,11,239,187,122,115,30,77,37,71,206,117,202,64,20,182,63,37,168,202,181,1,214,125,16,101,192,25,94,228,84,81,25,168,56,133,11,224,191,45,181,131,2,52,28,31,241,86,205,85,104,104,20,156,118,114,11,62,47,184,153,119,25,240,239,207,191,23,122,28,7,2,64,179,195,57,45,62,125,136,110,122,118,94,165,43,121,70,248,61,231,32,141,251,192,181,155,120,53,238,59,46,92,109,28,144,240,210,123,121,141,108,73,46,175,28,49,2,131,43,233,57,246,150,80,71,20,36,112,187,191,225,82,107,109,211,220,170,134,113,241,123,141,70,211,7,27,29,251,95,76,27,184,213,144,147,66,105,229,70,39,210,195,115,237,101,245,55,246,161,155,6,226,30,246,58,251,225,65,173,153,163,229,210,126,184,185,201,116,74,122,181,245,46,195,43,55,234,201,94,47,249,253,247,164,215,187,199,44,122,242,228,81,125,79,150,4,216,39,100,104,235,166,133,142,40,236,158,220,216,108,68,47,29,161,39,79,215,113,154,64,29,38,142,33,46,202,140,30,175,144,56,102,59,54,175,90,17,177,209,243,69,211,19,55,105,244,156,8,204,69,81,84,163,9,180,40,184,159,209,84,129,73,52,230,126,156,190,112,54,19,61,12,4,101,223,209,73,203,130,31,194,56,244,235,71,136,201,95,198,106,140,238,52,58,22,179,232,139,106,153,29,184,122,185,52,67,202,188,149,237,222,17,249,62,30,126,21,179,237,253,140,67,184,47,3,131,5,78,27,57,125,73,118,103,102,116,22,83,146,117,14,63,255,180,48,53,8,197,53,221,241,142,77,16,48,181,198,231,147,39,185,212,132,249,172,91,119,220,146,5,89,49,121,59,174,86,190,159,213,109,2,149,112,75,245,137,4,137,98,235,88,147,2,189,241,216,52,172,173,39,30,92,158,33,96,248,184,126,193,80,146,70,95,111,92,174,52,145,178,52,233,126,231,201,147,134,102,26,76,183,247,100,154,198,13,135,124,13,80,77,204,9,195,232,107,181,240,229,97,28,203,91,208,255,244,219,80,152,253,253,18,255,86,113,65,34,144,170,232,250,92,175,203,185,217,116,141,41,227,218,0,5,119,103,160,21,62,64,85,175,250,57,157,38,129,1,41,153,47,213,54,106,168,170,50,27,30,172,11,80,245,10,172,22,32,159,109,99,73,44,201,236,42,137,21,140,29,37,47,183,175,128,116,101,184,228,120,204,80,53,238,48,17,189,155,186,68,119,248,45,219,67,93,31,144,173,188,175,213,180,193,236,209,22,144,4,105,146,185,131,72,141,100,21,25,236,122,181,8,39,171,1,69,79,4,85,11,195,171,48,79,222,114,27,170,112,229,35,101,7,252,12,77,129,83,249,101,205,160,53,161,65,224,193,253,180,56,179,28,90,123,169,109,119,9,83,71,121,117,193,173,85,93,214,6,194,238,233,180,182,237,186,110,57,136,180,94,183,58,150,181,118,183,186,237,82,183,89,248,232,193,78,243,64,211,58,93,230,237,150,58,228,64,202,131,189,233,16,211,58,93,233,22,151,70,144,129,117,92,144,245,45,38,120,2,194,22,55,223,54,120,111,137,174,163,71,3,120,191,242,168,150,205,65,58,205,201,243,46,27,64,13,205,230,232,79,184,52,225,21,204,99,146,59,213,80,4,154,81,56,107,117,46,250,17,119,88,117,40,16,25,12,40,45,198,115,163,192,0,13,112,41,30,109,97,96,128,157,64,112,127,60,214,84,71,168,202,26,14,29,81,225,240,94,20,146,236,182,60,183,237,173,171,13,124,119,38,231,22,138,185,237,246,19,24,13,188,97,103,223,232,225,228,157,124,215,240,155,47,193,151,0,229,66,21,96,182,23,187,117,195,69,16,52,73,6,249,229,206,141,77,246,207,238,56,196,142,11,174,242,101,197,84,169,133,33,181,156,137,180,236,60,144,139,246,8,170,24,27,47,233,93,162,133,214,217,143,14,140,166,219,143,192,168,75,46,163,171,222,165,132,191,174,143,127,66,248,115,181,159,27,228,153,2,207,76,114,26,199,7,28,135,58,131,253,174,196,179,221,132,246,33,45,221,57,122,14,85,59,4,56,184,196,141,232,145,253,120,184,216,99,67,22,55,158,112,37,16,81,130,195,176,252,128,134,4,25,223,112,170,211,132,57,149,239,0,54,1,3,183,26,219,18,180,193,108,1,26,102,191,128,127,227,46,87,94,164,127,108,208,14,89,81,174,9,222,218,209,140,88,141,23,35,85,226,45,158,145,181,65,12,195,234,96,173,0,186,200,62,86,108,204,149,89,72,13,46,181,161,0,18,102,233,222,85,113,45,27,40,26,99,222,56,93,23,170,178,117,49,138,17,173,189,205,174,184,194,36,184,71,115,55,139,227,141,209,31,187,207,74,52,170,198,66,121,184,247,135,204,154,102,117,100,25,16,134,234,4,69,69,97,58,168,151,22,179,181,252,113,139,124,15,167,78,190,212,212,179,15,27,50,250,69,53,155,221,250,38,235,164,180,9,73,96,76,67,35,113,95,96,73,71,228,72,115,222,23,168,20,114,67,131,211,68,77,193,16,184,38,66,226,160,141,30,1,109,210,134,147,29,235,3,228,229,55,82,66,21,15,81,80,121,136,169,32,40,209,157,177,135,103,117,228,73,53,95,154,170,201,20,180,36,146,134,111,11,196,200,194,53,83,31,241,67,225,65,145,211,191,178,188,238,213,152,214,0,17,6,71,218,141,191,141,55,155,127,243,236,159,70,171,225,253,220,108,190,108,27,5,114,55,147,159,162,184,139,19,207,157,249,33,93,110,95,177,144,132,203,157,43,55,134,193,194,158,224,110,23,11,64,79,117,47,169,62,213,164,58,88,116,5,51,9,180,17,38,85,85,97,203,167,184,13,60,154,190,126,241,73,154,105,54,233,81,95,125,159,127,151,46,135,130,142,208,33,122,21,197,28,13,170,225,8,212,117,192,5,244,35,75,178,11,31,62,234,161,215,8,195,61,98,190,105,105,205,151,49,169,167,31,108,58,162,129,11,2,208,172,47,195,116,211,105,106,77,250,168,151,114,11,1,66,144,53,32,60,228,117,60,231,1,154,82,5,243,200,192,150,94,22,185,131,234,162,31,84,124,60,7,190,3,43,69,102,12,130,15,112,7,117,206,35,122,62,45,13,68,128,147,6,141,28,234,10,104,122,89,45,55,244,220,106,45,51,87,153,29,217,72,218,151,189,226,160,54,82,47,149,215,3,52,26,220,140,84,205,151,14,212,49,73,186,66,126,1,139,26,87,204,31,57,93,231,191,56,137,83,231,15,206,192,113,167,21,205,48,53,213,61,158,125,6,136,100,49,155,201,248,214,128,42,25,16,191,151,122,48,31,48,95,109,117,52,60,245,16,44,24,134,177,250,250,30,109,107,61,116,205,71,189,214,22,26,41,150,211,141,93,78,252,120,118,35,99,213,194,179,251,28,77,102,7,207,240,115,192,60,1,213,58,140,163,27,48,149,7,40,4,80,237,13,22,113,128,26,195,47,177,54,216,1,73,20,128,229,29,93,235,72,97,118,11,230,247,126,13,183,185,15,140,144,21,127,49,167,237,136,250,64,12,9,121,29,137,105,222,71,201,251,7,157,197,139,155,153,60,148,122,13,246,78,37,40,11,232,2,35,187,18,149,7,122,78,139,88,145,101,105,222,204,142,12,153,251,230,240,13,60,213,1,119,248,38,237,196,31,71,211,182,74,230,184,103,113,48,243,105,71,203,0,234,64,121,64,217,139,109,6,175,174,103,140,64,247,84,165,103,35,25,172,32,113,121,5,81,17,117,105,222,23,172,110,77,115,140,204,240,216,155,192,155,235,188,127,135,43,14,252,94,51,63,160,228,130,226,154,13,112,22,224,54,66,218,150,139,208,71,167,5,98,35,143,179,3,38,244,115,47,54,53,188,235,236,106,136,11,31,217,1,12,247,215,220,47,99,145,47,135,35,38,124,228,7,6,213,120,37,199,113,183,58,157,159,165,151,232,69,27,117,134,34,93,221,28,97,115,120,146,204,207,169,55,165,58,224,79,234,223,64,59,167,249,34,186,113,65,176,188,80,208,178,54,245,123,217,158,254,102,187,81,120,110,118,247,175,168,93,70,201,74,243,89,129,147,175,33,204,211,4,24,194,176,103,63,251,25,143,115,107,151,32,201,79,22,168,244,203,121,6,245,61,134,56,243,171,20,172,196,247,83,90,81,130,126,97,72,225,82,246,118,59,108,54,84,206,108,67,99,3,116,188,117,50,31,181,216,117,166,192,45,180,154,228,210,2,246,95,92,90,84,250,75,147,86,25,240,12,165,115,179,158,95,235,24,211,170,56,40,16,123,213,31,157,226,170,67,92,60,153,169,96,219,21,143,117,98,217,145,204,101,72,141,176,64,57,167,61,142,6,22,135,96,131,39,223,10,92,231,65,224,52,177,234,128,99,184,107,129,139,230,22,108,36,250,10,135,62,102,154,14,23,208,66,228,54,117,172,13,190,87,24,255,90,177,112,179,106,217,195,31,27,19,115,213,10,8,56,223,210,51,73,227,47,243,208,174,222,86,97,86,20,133,29,154,78,107,130,168,210,172,141,164,151,242,106,157,197,11,208,14,246,18,197,198,102,136,80,90,0,155,128,54,221,212,44,84,100,22,180,196,10,237,190,192,213,10,107,53,162,233,230,11,17,14,234,187,98,120,191,112,52,171,99,162,224,53,54,243,28,230,85,163,34,139,31,117,204,249,33,10,57,57,173,181,121,241,80,138,255,108,153,134,0,106,152,184,208,20,30,240,5,146,53,109,55,182,126,54,133,116,88,90,163,137,182,39,29,79,67,51,143,4,161,212,139,229,69,17,233,55,237,197,209,198,29,204,99,210,59,251,102,82,219,167,74,162,67,16,225,198,88,96,163,194,144,41,94,121,199,205,54,4,7,112,212,82,215,93,204,27,69,245,138,113,48,46,2,37,188,178,12,167,74,177,139,39,79,202,29,144,224,97,89,230,100,66,141,159,198,242,166,197,120,225,144,80,138,101,213,98,189,195,68,5,123,21,194,16,177,176,20,97,30,250,48,53,187,102,220,192,40,132,209,238,18,7,101,118,43,7,175,212,101,177,25,218,69,216,188,2,179,194,38,180,50,240,103,71,239,166,181,220,83,24,28,93,183,91,180,168,245,83,135,142,162,97,154,208,218,239,170,38,173,85,228,181,155,52,146,173,220,26,186,210,196,217,148,253,64,25,200,232,140,107,201,244,210,22,231,224,4,22,36,104,195,52,93,16,92,45,242,80,107,193,46,180,85,43,242,140,27,137,133,120,222,155,62,8,136,154,2,117,243,24,207,225,213,209,97,164,141,251,0,26,247,6,149,87,5,132,29,7,143,49,50,184,105,95,125,93,194,161,207,238,163,203,96,159,76,4,179,185,222,109,206,234,229,186,35,43,170,132,23,188,33,30,103,68,245,239,33,145,87,191,110,234,214,200,179,44,148,144,198,89,144,3,91,206,214,194,101,175,179,47,15,94,236,203,205,205,102,22,89,200,195,14,134,130,32,224,253,254,129,212,199,139,63,214,26,134,42,23,68,115,31,127,64,14,75,112,7,224,13,135,34,28,117,40,20,250,1,226,11,233,212,69,13,11,51,11,223,41,205,129,28,2,135,151,17,43,163,133,210,74,59,112,118,251,213,108,44,144,10,152,94,82,151,214,198,185,30,240,214,114,89,182,215,116,80,209,185,114,179,160,232,70,38,204,252,122,254,242,171,177,178,94,30,149,210,161,177,108,253,25,74,65,2,196,184,147,160,11,2,156,182,85,158,204,230,233,45,243,12,62,139,96,140,222,135,175,162,209,34,193,91,174,252,62,252,5,28,20,188,7,254,196,131,121,239,24,214,110,93,80,4,176,58,64,243,37,115,249,74,135,58,58,246,224,247,239,95,154,135,9,111,252,65,102,4,108,24,92,195,58,181,100,199,135,107,135,174,102,74,234,23,42,1,76,86,60,21,206,175,28,65,233,52,87,50,10,47,139,216,246,85,229,229,62,27,25,27,249,2,136,153,35,14,81,176,79,41,156,234,43,165,125,242,3,104,214,212,145,112,13,70,124,20,242,224,29,142,199,165,225,72,43,209,103,52,230,43,15,205,130,245,119,36,254,185,247,164,19,46,235,99,180,203,98,152,63,143,51,91,108,139,139,1,245,28,155,68,113,74,246,108,87,199,138,107,121,248,255,61,166,61,29,255,41,56,86,47,156,240,242,206,190,254,237,101,201,181,210,94,150,96,113,174,151,17,36,188,237,22,114,19,78,1,220,134,110,161,102,201,130,89,228,21,69,223,186,181,163,161,227,206,255,167,209,249,122,41,91,147,195,214,171,78,235,197,213,221,150,251,116,249,251,165,190,220,93,54,127,106,55,95,54,50,8,161,171,206,1,198,47,213,65,111,111,119,119,103,247,101,163,176,38,129,121,15,232,2,116,75,143,57,41,115,136,219,128,120,183,188,138,179,157,68,157,175,29,60,75,30,55,8,117,190,190,130,127,14,14,87,243,71,180,177,180,83,52,122,217,85,97,134,238,115,32,98,227,96,145,249,100,161,252,2,94,214,151,86,42,135,9,187,94,180,157,244,2,111,193,51,132,26,218,44,217,215,231,28,214,174,177,135,228,235,101,51,137,115,198,172,105,182,129,172,36,175,43,62,40,244,138,182,129,242,204,230,15,219,72,192,206,209,133,211,141,91,205,85,22,216,107,90,253,120,124,150,53,181,129,109,64,203,11,240,9,185,57,107,98,96,99,122,189,180,128,177,192,221,26,15,34,93,106,8,166,9,30,52,5,138,93,231,205,105,103,86,99,207,237,59,249,17,140,181,249,93,254,132,130,217,67,140,243,193,123,102,46,21,58,203,63,181,129,41,140,18,209,35,39,215,149,185,219,13,117,40,27,44,235,28,46,109,66,107,47,25,156,63,220,89,131,153,85,37,140,242,195,217,53,133,241,178,133,50,129,219,197,91,26,104,45,73,92,153,123,219,110,93,154,79,15,4,2,186,102,47,185,43,102,204,162,156,102,159,85,216,41,119,98,101,218,144,48,81,11,32,108,121,239,78,125,50,8,2,200,186,163,79,129,172,131,182,185,91,26,240,185,107,144,118,214,78,166,127,8,112,123,8,242,189,57,63,0,62,188,47,237,26,204,0,173,13,29,241,34,9,12,184,89,145,199,76,29,147,85,112,183,108,118,139,57,163,116,124,106,125,54,110,25,51,76,200,181,71,31,38,135,92,242,228,205,226,47,205,218,185,87,59,101,42,51,156,231,112,213,171,75,90,116,114,188,176,14,144,183,60,26,189,158,106,67,81,184,38,239,216,228,80,228,123,116,194,102,185,36,89,12,103,126,90,24,42,138,242,214,250,157,213,252,31,111,42,147,146,151,215,172,102,19,97,0,194,156,197,156,246,202,16,168,216,7,247,224,191,21,167,85,130,87,2,35,125,79,202,130,186,228,85,167,171,108,221,178,148,152,41,155,47,165,55,95,36,211,76,181,118,179,119,122,151,160,133,249,233,149,245,84,63,162,44,134,194,145,24,221,203,171,37,45,113,123,192,49,72,193,187,234,100,197,58,168,218,255,25,201,43,41,6,59,172,61,5,166,105,102,14,10,125,193,111,195,193,32,131,163,45,164,154,8,1,178,120,253,96,235,182,235,198,172,206,4,91,201,167,43,65,177,62,132,177,114,149,22,170,29,248,100,139,214,199,156,45,187,149,14,51,164,181,54,255,26,253,245,52,138,80,80,54,238,232,204,102,60,131,185,235,96,128,218,165,111,44,148,188,231,76,202,59,188,185,64,250,32,74,186,236,175,47,209,117,215,145,11,182,4,77,52,236,177,222,34,94,8,93,213,174,141,55,11,41,215,141,154,128,135,142,114,252,177,207,176,46,128,81,242,210,171,240,84,210,96,242,77,101,0,227,170,172,164,75,152,191,233,147,39,143,10,187,154,158,60,41,236,247,171,241,3,255,184,199,109,231,7,152,163,229,153,27,161,67,180,76,249,171,81,250,124,86,48,43,108,247,197,240,97,241,177,126,133,63,226,5,69,122,95,1,171,47,190,113,74,117,245,190,215,162,201,56,138,130,64,206,147,236,177,140,175,241,251,136,230,67,86,89,113,191,232,89,198,45,60,100,204,233,243,18,43,34,224,95,147,172,210,30,147,40,84,167,153,9,205,57,253,31,82,156,237,108,16,96,25,23,113,164,15,111,153,207,52,182,157,226,151,29,165,182,215,138,228,101,4,69,21,225,138,175,128,229,240,67,159,22,180,140,242,76,156,23,41,203,98,175,72,214,178,124,238,27,89,144,89,236,165,166,41,70,204,222,9,93,62,224,181,211,178,28,9,74,38,97,191,184,32,152,209,47,239,204,180,150,133,56,173,222,233,136,114,167,92,163,158,143,178,247,5,88,73,22,11,98,190,71,11,140,128,121,52,95,204,123,124,160,3,63,84,95,1,150,177,2,212,248,84,135,62,159,185,94,24,250,17,76,187,212,26,119,105,143,74,225,131,114,229,65,33,216,91,252,225,153,181,70,166,240,130,25,158,67,190,45,16,140,241,75,20,136,4,137,103,238,102,224,248,95,124,158,139,213,113,164,21,24,189,182,163,189,77,91,105,172,1,158,169,174,1,35,197,66,7,144,104,213,178,130,129,178,46,215,237,161,149,165,224,232,158,184,125,241,74,63,94,209,15,46,152,87,182,154,213,118,195,53,91,229,137,240,11,61,206,91,71,151,213,190,226,29,85,252,23,230,224,10,17,73,148,205,124,90,187,14,110,26,165,210,60,213,81,171,30,252,184,101,89,228,6,173,100,214,218,65,158,202,253,201,162,158,171,111,203,233,115,128,70,188,3,179,209,248,153,198,105,202,223,200,26,33,37,140,39,55,41,232,224,136,194,57,124,54,160,231,121,196,246,236,241,20,208,47,94,218,248,173,141,196,233,184,12,63,39,93,26,232,79,199,197,105,104,37,142,230,115,113,21,114,216,120,1,175,19,218,166,59,93,12,113,147,110,5,169,42,200,79,139,136,216,185,157,212,77,97,67,49,115,23,225,54,26,165,110,124,61,188,193,63,3,188,153,44,210,206,243,23,244,243,98,171,72,7,29,15,118,250,100,59,100,200,172,78,36,48,47,172,72,37,120,96,189,223,108,83,236,175,222,153,104,22,78,30,218,150,184,5,2,135,215,115,123,217,130,124,95,108,101,40,124,83,226,193,119,65,176,13,253,109,255,11,251,3,22,22,59,255,194,254,128,255,196,211,53,251,19,5,238,204,121,145,89,239,71,64,179,11,208,236,254,97,160,217,3,104,246,254,48,208,60,3,104,158,253,97,160,121,14,208,60,255,23,242,105,7,250,59,12,130,172,199,130,142,188,71,182,90,98,144,66,124,253,15,106,22,129,226,193,184,67,157,36,180,76,195,21,187,151,245,121,148,21,11,177,232,141,212,219,139,26,158,62,58,193,185,82,185,199,6,212,182,255,74,67,144,196,53,35,134,230,154,77,49,212,14,197,69,48,60,44,173,96,221,217,213,65,135,20,107,31,29,93,172,172,172,149,78,102,14,102,18,191,216,219,230,3,109,84,94,88,89,57,99,92,171,62,159,238,38,218,226,151,231,247,190,71,234,176,244,222,139,45,124,111,187,108,130,221,199,84,171,140,142,173,237,123,84,120,62,245,10,202,26,126,221,12,165,117,251,152,238,246,95,47,128,109,224,247,91,97,220,43,185,180,121,218,216,202,2,157,79,86,239,165,86,115,73,115,150,213,63,21,82,174,0,121,53,185,44,179,230,219,168,116,158,101,36,127,55,177,88,94,153,0,0,229,173,9,43,99,77,84,82,159,25,116,174,137,31,87,68,137,85,124,38,191,130,61,211,41,61,53,118,14,60,255,62,58,105,110,170,53,1,191,129,100,148,106,40,46,242,188,231,239,166,156,245,180,242,161,238,181,9,107,39,96,255,115,40,251,109,211,27,104,145,167,109,127,23,105,168,153,245,144,231,44,240,31,141,246,55,49,3,229,22,254,3,136,230,234,42,75,158,204,157,7,191,104,14,100,217,157,162,176,43,34,235,199,162,79,113,253,87,235,221,170,131,192,18,189,126,238,8,254,88,239,74,201,156,201,27,108,226,190,56,99,213,230,178,243,68,185,121,253,132,86,219,7,52,27,156,254,111,248,147,43,118,86,62,68,220,117,123,68,215,244,190,206,66,218,213,194,70,193,59,188,46,245,182,54,102,188,3,230,190,174,230,210,143,31,14,211,45,18,29,166,59,131,234,223,9,140,62,52,230,30,88,22,225,58,208,216,71,199,136,143,244,74,121,48,208,18,152,195,239,252,126,62,254,22,254,210,252,100,189,82,254,114,251,3,81,237,178,245,137,215,250,172,225,251,134,7,243,200,163,69,162,153,161,160,194,235,136,67,240,212,69,158,237,23,105,45,201,209,38,172,182,13,254,113,208,5,157,107,130,159,165,40,115,179,250,154,174,11,191,97,181,146,241,108,11,41,211,75,73,27,228,179,240,7,136,141,127,157,59,129,131,112,127,16,249,1,7,66,20,83,126,139,118,240,247,17,165,46,44,245,63,196,255,124,196,52,126,89,97,160,209,251,145,51,224,28,27,254,129,83,224,30,232,137,62,255,10,238,175,184,65,248,54,133,4,107,215,185,45,166,144,1,165,119,152,37,145,177,47,131,232,186,34,38,101,208,90,93,82,27,203,230,162,181,150,254,120,99,2,83,17,252,146,153,159,189,239,244,159,208,49,194,251,57,89,166,219,197,30,244,160,154,175,144,242,118,1,52,129,182,235,39,129,73,67,121,208,40,18,182,97,132,185,7,53,244,228,156,132,254,65,74,7,159,231,105,51,8,209,65,138,200,247,241,192,62,184,204,162,214,199,7,109,184,195,39,248,57,189,179,40,78,179,7,103,113,132,177,148,64,232,77,211,89,65,190,130,88,214,241,6,28,220,127,65,172,136,48,150,54,99,172,173,231,217,171,198,254,240,236,53,188,98,4,144,94,117,200,155,45,27,88,21,235,224,47,226,14,191,72,151,135,156,201,124,165,224,73,56,76,230,251,37,206,45,45,190,252,249,88,54,95,86,93,139,87,171,84,90,199,162,39,198,229,5,67,218,2,98,83,182,20,223,227,196,154,85,230,100,182,157,239,156,171,125,235,32,103,33,39,60,121,83,208,223,214,141,140,105,139,58,223,13,131,104,244,89,39,152,21,182,31,173,53,20,149,215,244,126,167,154,225,120,218,191,224,138,66,31,4,45,26,244,97,17,76,218,53,159,17,108,194,168,60,181,152,177,116,98,244,42,36,243,69,211,242,26,229,159,143,127,43,139,174,223,36,114,107,248,192,33,251,125,216,63,12,48,47,79,164,242,179,18,82,100,33,192,182,149,195,160,79,86,200,121,217,163,244,179,62,47,220,226,241,243,183,209,2,211,61,243,204,5,49,84,19,252,148,203,98,126,29,211,81,68,158,0,20,251,231,209,76,241,81,245,92,128,159,63,225,15,139,241,105,245,188,39,52,113,245,23,57,240,203,33,163,40,142,23,115,254,194,28,229,230,208,166,64,79,156,78,248,19,49,83,202,189,130,87,72,111,115,59,46,112,22,248,195,8,180,126,143,169,230,106,174,75,82,254,204,140,18,43,80,240,200,177,89,103,58,17,25,143,53,133,178,142,196,208,15,37,158,177,100,62,121,169,114,202,154,195,23,172,131,23,30,62,114,1,116,174,159,190,94,12,133,121,32,112,51,45,82,218,19,249,202,191,20,161,117,196,199,16,188,109,204,60,163,111,20,240,209,30,78,37,75,192,17,204,120,140,49,113,196,91,100,133,100,97,40,132,152,220,154,239,188,49,81,233,251,24,146,156,222,57,125,56,2,27,36,2,210,183,162,31,225,80,103,172,202,159,16,242,67,172,44,83,127,72,159,207,209,103,117,142,232,235,31,58,103,80,208,49,13,53,35,11,100,35,238,32,112,232,99,212,212,228,199,243,95,236,113,42,8,223,182,25,9,71,112,66,37,30,223,150,128,188,85,225,136,231,40,167,75,203,56,37,201,218,194,201,89,156,51,118,90,87,105,241,198,42,210,74,223,54,59,141,44,159,199,62,157,237,209,255,133,142,40,17,5,249,79,25,103,58,152,195,215,73,122,203,2,138,98,197,221,48,10,85,117,109,125,205,148,100,76,114,195,116,44,208,87,250,234,251,80,48,234,8,196,15,241,119,54,166,181,186,108,45,12,180,16,183,213,89,69,128,77,128,17,30,148,170,37,127,97,133,124,61,66,217,107,5,47,238,209,153,118,14,206,159,91,141,172,171,61,144,34,229,147,106,204,123,211,152,148,187,222,28,151,91,209,182,34,47,31,223,84,166,118,241,152,27,135,26,124,67,207,170,237,153,128,48,7,62,239,111,201,36,166,48,203,101,77,85,23,50,179,211,160,152,170,112,133,30,5,31,157,148,245,193,175,125,96,193,43,142,137,126,235,53,149,125,62,117,32,211,21,205,189,139,40,85,75,183,55,143,213,125,237,233,161,161,111,101,112,214,143,92,81,29,143,103,232,241,49,73,214,251,184,5,0,207,71,114,250,127,245,65,81,0,163,177,86,41,38,66,214,182,138,68,46,158,197,148,107,189,98,38,216,195,86,233,255,244,36,175,79,56,251,243,77,118,206,160,19,79,196,7,109,241,124,171,19,116,48,221,201,230,29,127,53,185,212,180,213,224,78,255,91,108,199,213,186,178,220,112,145,51,87,2,84,131,226,78,217,38,200,193,250,255,54,193,143,179,9,126,168,41,240,135,147,21,117,73,192,127,62,73,193,137,214,89,110,243,195,210,33,143,148,51,105,74,75,151,247,126,211,128,152,104,38,172,211,93,74,49,93,116,208,96,18,242,164,150,241,61,75,115,223,217,1,185,138,133,243,207,129,45,208,123,196,111,243,9,222,206,84,183,224,245,135,225,206,182,142,0,162,66,239,255,95,211,171,167,180,238,162,0,0}; \ No newline at end of file diff --git a/lib/Settings/Settings.cpp b/lib/Settings/Settings.cpp index b2251829..486ff2b5 100644 --- a/lib/Settings/Settings.cpp +++ b/lib/Settings/Settings.cpp @@ -98,6 +98,7 @@ void Settings::patch(JsonObject parsedSettings) { this->setIfPresent(parsedSettings, "wifi_static_ip_gateway", wifiStaticIPGateway); this->setIfPresent(parsedSettings, "wifi_static_ip_netmask", wifiStaticIPNetmask); this->setIfPresent(parsedSettings, "packet_repeats_per_loop", packetRepeatsPerLoop); + this->setIfPresent(parsedSettings, "home_assistant_discovery_prefix", homeAssistantDiscoveryPrefix); if (parsedSettings.containsKey("rf24_channels")) { JsonArray arr = parsedSettings["rf24_channels"]; @@ -271,6 +272,7 @@ void Settings::serialize(Print& stream, const bool prettyPrint) { root["wifi_static_ip_gateway"] = this->wifiStaticIPGateway; root["wifi_static_ip_netmask"] = this->wifiStaticIPNetmask; root["packet_repeats_per_loop"] = this->packetRepeatsPerLoop; + root["home_assistant_discovery_prefix"] = this->homeAssistantDiscoveryPrefix; JsonArray channelArr = root.createNestedArray("rf24_channels"); JsonHelpers::vectorToJsonArr(channelArr, rf24Channels, RF24ChannelHelpers::nameFromValue); diff --git a/lib/Settings/Settings.h b/lib/Settings/Settings.h index 812c6e27..d469ae3e 100644 --- a/lib/Settings/Settings.h +++ b/lib/Settings/Settings.h @@ -183,6 +183,7 @@ class Settings { String wifiStaticIPGateway; size_t packetRepeatsPerLoop; std::map groupIdAliases; + String homeAssistantDiscoveryPrefix; protected: size_t _autoRestartPeriod; diff --git a/web/src/js/script.js b/web/src/js/script.js index 5b508510..140cff63 100644 --- a/web/src/js/script.js +++ b/web/src/js/script.js @@ -186,6 +186,12 @@ var UI_FIELDS = [ { false: "Detailed" }, tab: "tab-mqtt" + }, { + tag: "home_assistant_discovery_prefix", + friendly: "HomeAssistant MQTT Discovery Prefix", + help: "If set, will enable integration with HomeAssistant's MQTT discovery functionality to allow saved aliases to be detected automatically", + type: "string", + tab: "tab-mqtt" }, { tag: "radio_interface_type", friendly: "Radio interface type", From 30f3f230905a581d89fe9f9b5dd11322a9da986f Mon Sep 17 00:00:00 2001 From: Christopher Mullins Date: Sat, 22 Jun 2019 14:59:30 -0700 Subject: [PATCH 02/17] Add ability to inject callback for when MQTT client connects --- lib/MQTT/MqttClient.cpp | 20 ++++++++++++++++++-- lib/MQTT/MqttClient.h | 6 ++++++ src/main.cpp | 7 +++++++ test/remote/spec/settings_spec.rb | 3 ++- 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/lib/MQTT/MqttClient.cpp b/lib/MQTT/MqttClient.cpp index bb6b9a54..15a5b6c2 100644 --- a/lib/MQTT/MqttClient.cpp +++ b/lib/MQTT/MqttClient.cpp @@ -16,7 +16,8 @@ MqttClient::MqttClient(Settings& settings, MiLightClient*& milightClient) : mqttClient(tcpClient), milightClient(milightClient), settings(settings), - lastConnectAttempt(0) + lastConnectAttempt(0), + connected(false) { String strDomain = settings.mqttServer(); this->domain = new char[strDomain.length() + 1]; @@ -30,6 +31,10 @@ MqttClient::~MqttClient() { delete this->domain; } +void MqttClient::onConnect(OnConnectFn fn) { + this->onConnectFn = fn; +} + void MqttClient::begin() { #ifdef MQTT_DEBUG printf_P( @@ -117,6 +122,13 @@ void MqttClient::reconnect() { void MqttClient::handleClient() { reconnect(); mqttClient.loop(); + + if (!connected && mqttClient.connected()) { + this->connected = true; + this->onConnectFn(); + } else if (!mqttClient.connected()) { + this->connected = false; + } } void MqttClient::sendUpdate(const MiLightRemoteConfig& remoteConfig, uint16_t deviceId, uint16_t groupId, const char* update) { @@ -144,6 +156,10 @@ void MqttClient::subscribe() { mqttClient.subscribe(topic.c_str()); } +void MqttClient::send(const char* topic, const char* message, const bool retain) { + mqttClient.publish(topic, message, retain); +} + void MqttClient::publish( const String& _topic, const MiLightRemoteConfig &remoteConfig, @@ -163,7 +179,7 @@ void MqttClient::publish( printf("MqttClient - publishing update to %s\n", topic.c_str()); #endif - mqttClient.publish(topic.c_str(), message, retain); + send(topic.c_str(), message, retain); } void MqttClient::publishCallback(char* topic, byte* payload, int length) { diff --git a/lib/MQTT/MqttClient.h b/lib/MQTT/MqttClient.h index 00655c16..7a905d44 100644 --- a/lib/MQTT/MqttClient.h +++ b/lib/MQTT/MqttClient.h @@ -13,6 +13,8 @@ class MqttClient { public: + using OnConnectFn = std::function; + MqttClient(Settings& settings, MiLightClient*& milightClient); ~MqttClient(); @@ -21,6 +23,8 @@ class MqttClient { void reconnect(); void sendUpdate(const MiLightRemoteConfig& remoteConfig, uint16_t deviceId, uint16_t groupId, const char* update); void sendState(const MiLightRemoteConfig& remoteConfig, uint16_t deviceId, uint16_t groupId, const char* update); + void send(const char* topic, const char* message, const bool retain = false); + void onConnect(OnConnectFn fn); private: WiFiClient tcpClient; @@ -29,6 +33,8 @@ class MqttClient { Settings& settings; char* domain; unsigned long lastConnectAttempt; + OnConnectFn onConnectFn; + bool connected; void sendBirthMessage(); bool connect(); diff --git a/src/main.cpp b/src/main.cpp index f457147b..762ad255 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -239,6 +239,13 @@ void applySettings() { if (settings.mqttServer().length() > 0) { mqttClient = new MqttClient(settings, milightClient); mqttClient->begin(); + mqttClient->onConnect([settings, mqttClient]() { + if (settings.homeAssistantDiscoveryPrefix.length() > 0) { + HomeAssistantDiscoveryClient discoveryClient(settings, mqttClient); + discoveryClient.sendDiscoverableDevices(settings.groupIdAliases); + } + }); + bulbStateUpdater = new BulbStateUpdater(settings, *mqttClient, *stateStore); } diff --git a/test/remote/spec/settings_spec.rb b/test/remote/spec/settings_spec.rb index 1ab3745e..8886ac2b 100644 --- a/test/remote/spec/settings_spec.rb +++ b/test/remote/spec/settings_spec.rb @@ -27,7 +27,8 @@ it 'should persist known settings keys' do { 'simple_mqtt_client_status' => [true, false], - 'packet_repeats_per_loop' => [10] + 'packet_repeats_per_loop' => [10], + 'home_assistant_discovery_prefix' => ['', 'abc', 'a/b/c'] }.each do |key, values| values.each do |v| @client.patch_settings({key => v}) From d2ce61d8b31d181590bf7ab7a27a05b2680c9ba8 Mon Sep 17 00:00:00 2001 From: Christopher Mullins Date: Sat, 22 Jun 2019 14:59:56 -0700 Subject: [PATCH 03/17] Initial pass at HASS discovery client --- lib/MQTT/HomeAssistantDiscoveryClient.cpp | 135 ++++++++++++++++++++++ lib/MQTT/HomeAssistantDiscoveryClient.h | 22 ++++ src/main.cpp | 1 + test/remote/spec/discovery_spec.rb | 118 +++++++++++++++++++ 4 files changed, 276 insertions(+) create mode 100644 lib/MQTT/HomeAssistantDiscoveryClient.cpp create mode 100644 lib/MQTT/HomeAssistantDiscoveryClient.h create mode 100644 test/remote/spec/discovery_spec.rb diff --git a/lib/MQTT/HomeAssistantDiscoveryClient.cpp b/lib/MQTT/HomeAssistantDiscoveryClient.cpp new file mode 100644 index 00000000..e2e33272 --- /dev/null +++ b/lib/MQTT/HomeAssistantDiscoveryClient.cpp @@ -0,0 +1,135 @@ +#include + +HomeAssistantDiscoveryClient::HomeAssistantDiscoveryClient(Settings& settings, MqttClient* mqttClient) + : settings(settings) + , mqttClient(mqttClient) +{ } + +void HomeAssistantDiscoveryClient::sendDiscoverableDevices(const std::map& aliases) { +#ifdef MQTT_DEBUG + Serial.println(F("HomeAssistantDiscoveryClient: Sending discoverable devices...")); +#endif + + for (auto itr = aliases.begin(); itr != aliases.end(); ++itr) { + addConfig(itr->first.c_str(), itr->second); + } +} + +void HomeAssistantDiscoveryClient::removeConfig(const char* alias, const BulbId& bulbId) { + // Remove by publishing an empty message + String topic = buildTopic(bulbId); + mqttClient->send(topic.c_str(), "", true); +} + +void HomeAssistantDiscoveryClient::addConfig(const char* alias, const BulbId& bulbId) { + String topic = buildTopic(bulbId); + DynamicJsonDocument config(1024); + + config[F("schema")] = F("json"); + config[F("name")] = alias; + config[F("command_topic")] = bindTopicVariables(settings.mqttTopicPattern, alias, bulbId); + config[F("state_topic")] = bindTopicVariables(settings.mqttStateTopicPattern, alias, bulbId); + + // HomeAssistant only supports simple client availability + if (settings.mqttClientStatusTopic.length() > 0 && settings.simpleMqttClientStatus) { + config[F("availability_topic")] = settings.mqttClientStatusTopic; + config[F("payload_available")] = F("connected"); + config[F("payload_not_available")] = F("disconnected"); + } + + // Configure supported commands based on the bulb type + + // All supported bulbs support brightness and night mode + config[F("brightness")] = true; + config[F("effect")] = true; + + JsonArray effects = config.createNestedArray(F("effect_list")); + effects.add(F("night_mode")); + + // These bulbs support RGB color + switch (bulbId.deviceType) { + case REMOTE_TYPE_FUT089: + case REMOTE_TYPE_RGB: + case REMOTE_TYPE_RGB_CCT: + case REMOTE_TYPE_RGBW: + config[F("rgb")] = true; + break; + default: + break; //nothing + } + + // These bulbs support adjustable white values + switch (bulbId.deviceType) { + case REMOTE_TYPE_CCT: + case REMOTE_TYPE_FUT089: + case REMOTE_TYPE_FUT091: + case REMOTE_TYPE_RGB_CCT: + config[F("color_temp")] = true; + break; + default: + break; //nothing + } + + // These bulbs support switching between rgb/white, and have a "white_mode" command + switch (bulbId.deviceType) { + case REMOTE_TYPE_FUT089: + case REMOTE_TYPE_RGB_CCT: + case REMOTE_TYPE_RGBW: + effects.add(F("white_mode")); + break; + default: + break; //nothing + } + + String message; + serializeJson(config, message); + +#ifdef MQTT_DEBUG + Serial.printf_P(PSTR("HomeAssistantDiscoveryClient: adding discoverable device: %s...\n"), alias); + Serial.printf_P(PSTR(" topic: %s\nconfig: %s\n"), topic.c_str(), message.c_str()); +#endif + + + mqttClient->send(topic.c_str(), message.c_str(), true); +} + +// Topic syntax: +// //[/]/config +// +// source: https://www.home-assistant.io/docs/mqtt/discovery/ +String HomeAssistantDiscoveryClient::buildTopic(const BulbId& bulbId) { + String topic = settings.homeAssistantDiscoveryPrefix; + + // Don't require the user to entier a "/" (or break things if they do) + if (! topic.endsWith("/")) { + topic += "/"; + } + + topic += "light/"; + // Use a static ID that doesn't depend on configuration. + topic += "milight_hub_" + (ESP.getChipId()); + + // make the object ID based on the actual parameters rather than the alias. + topic += "/"; + topic += MiLightRemoteTypeHelpers::remoteTypeToString(bulbId.deviceType); + topic += "_0x"; + topic += String(bulbId.deviceId, HEX); + topic += "_"; + topic += bulbId.groupId; + topic += "/config"; + + return topic; +} + +String HomeAssistantDiscoveryClient::bindTopicVariables(const String& topic, const char* alias, const BulbId& bulbId) { + String boundTopic = topic; + + boundTopic.replace(":device_alias", alias); + boundTopic.replace(":device_id", String("0x") + String(bulbId.deviceId, HEX)); + boundTopic.replace(":hex_device_id", String("0x") + String(bulbId.deviceId, HEX)); + boundTopic.replace(":dec_device_id", String(bulbId.deviceId)); + boundTopic.replace(":device_type", MiLightRemoteTypeHelpers::remoteTypeToString(bulbId.deviceType)); + boundTopic.replace(":group_id", String(bulbId.groupId)); + + return boundTopic; +} \ No newline at end of file diff --git a/lib/MQTT/HomeAssistantDiscoveryClient.h b/lib/MQTT/HomeAssistantDiscoveryClient.h new file mode 100644 index 00000000..9fb474ab --- /dev/null +++ b/lib/MQTT/HomeAssistantDiscoveryClient.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include +#include + +class HomeAssistantDiscoveryClient { +public: + HomeAssistantDiscoveryClient(Settings& settings, MqttClient* mqttClient); + + void addConfig(const char* alias, const BulbId& bulbId); + void removeConfig(const char* alias, const BulbId& bulbId); + + void sendDiscoverableDevices(const std::map& aliases); + +private: + Settings& settings; + MqttClient* mqttClient; + + String buildTopic(const BulbId& bulbId); + String bindTopicVariables(const String& topic, const char* alias, const BulbId& bulbId); +}; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 762ad255..ead912bf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include diff --git a/test/remote/spec/discovery_spec.rb b/test/remote/spec/discovery_spec.rb new file mode 100644 index 00000000..c8b00737 --- /dev/null +++ b/test/remote/spec/discovery_spec.rb @@ -0,0 +1,118 @@ +require 'api_client' + +RSpec.describe 'MQTT Discovery' do + before(:all) do + @client = ApiClient.new(ENV.fetch('ESPMH_HOSTNAME'), ENV.fetch('ESPMH_TEST_DEVICE_ID_BASE')) + @client.upload_json('/settings', 'settings.json') + end + + before(:each) do + mqtt_params = mqtt_parameters() + @topic_prefix = mqtt_topic_prefix() + @discovery_prefix = "#{@topic_prefix}/discovery" + + @client.put( + '/settings', + mqtt_params + ) + + @id_params = { + id: @client.generate_id, + type: 'rgb_cct', + group_id: 1 + } + @discovery_suffix = "#{@id_params[:type]}_#{sprintf("%x", @id_params[:id])}_#{@id_params[:group_id]}" + + @mqtt_client = create_mqtt_client() + end + + context 'when not configured' do + it 'should behave appropriately when MQTT is not configured' do + @client.patch_settings(mqtt_server: '', home_assistant_discovery_prefix: '') + expect { @client.get('/settings') }.to_not raise_error + end + + it 'should behave appropriately when MQTT is configured, but discovery is not' do + @client.patch_settings(mqtt_parameters().merge(home_assistant_discovery_prefix: '')) + expect { @client.get('/settings') }.to_not raise_error + end + end + + context 'discovery topics' do + it 'should send discovery messages' do + saw_message = false + + @mqtt_client.on_message("#{@discovery_prefix}/light/+/#{@discovery_suffix}") do |topic, message| + saw_message = true + end + + @client.patch_settings( + home_assistant_discovery_prefix: @discovery_prefix, + group_id_aliases: { + 'test_group' => [@id_params[:type], @id_params[:id], @id_params[:group_id]] + } + ) + + expect(saw_message).to be_true + end + + it 'config should have expected keys' do + saw_message = false + config = nil + + @mqtt_client.on_message("#{@discovery_prefix}/light/+/#{@discovery_suffix}") do |topic, message| + config = JSON.parse(message) + saw_message = true + end + + @client.patch_settings( + home_assistant_discovery_prefix: @discovery_prefix, + group_id_aliases: { + 'test_group' => [@id_params[:type], @id_params[:id], @id_params[:group_id]] + } + ) + + expect(saw_message).to be_true + expected_keys = %w( + schema + name + command_topic + state_topic + availability_topic + payload_available + payload_not_available + brightness + rgb + color_temp + effect + effect_list + ) + expect(config.keys).to include(*expected_keys) + end + + it 'should remove discoverable devices when alias is removed' do + seen_config = false + seen_blank_message = false + + @mqtt_client.on_message("#{@discovery_prefix}/light/+/#{@discovery_suffix}") do |topic, message| + seen_config = message.length > 0 + seen_blank_message = message.empty? + + seen_config && seen_blank_message + end + + # This should create the device + @client.patch_settings( + home_assistant_discovery_prefix: @discovery_prefix, + group_id_aliases: { + 'test_group' => [@id_params[:type], @id_params[:id], @id_params[:group_id]] + } + ) + + # This should clear it + @client.patch_settings( + group_id_aliases: { } + ) + end + end +end \ No newline at end of file From 410bcb7b92d2d14d540301762f922807fa124075 Mon Sep 17 00:00:00 2001 From: Christopher Mullins Date: Sun, 23 Jun 2019 10:06:30 -0700 Subject: [PATCH 04/17] Add chunk size constant --- lib/MQTT/MqttClient.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/MQTT/MqttClient.h b/lib/MQTT/MqttClient.h index 7a905d44..f907b452 100644 --- a/lib/MQTT/MqttClient.h +++ b/lib/MQTT/MqttClient.h @@ -8,6 +8,10 @@ #define MQTT_CONNECTION_ATTEMPT_FREQUENCY 5000 #endif +#ifndef MQTT_PACKET_CHUNK_SIZE +#define MQTT_PACKET_CHUNK_SIZE 128 +#endif + #ifndef _MQTT_CLIENT_H #define _MQTT_CLIENT_H From fea8148775ddc962b42b41f612211547b00f8a1c Mon Sep 17 00:00:00 2001 From: Christopher Mullins Date: Sun, 23 Jun 2019 10:07:55 -0700 Subject: [PATCH 05/17] Expose method to generate compact ID --- lib/MiLightState/GroupStatePersistence.cpp | 2 +- lib/Types/BulbId.cpp | 5 +++++ lib/Types/BulbId.h | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/MiLightState/GroupStatePersistence.cpp b/lib/MiLightState/GroupStatePersistence.cpp index 99c3d478..14a1f718 100644 --- a/lib/MiLightState/GroupStatePersistence.cpp +++ b/lib/MiLightState/GroupStatePersistence.cpp @@ -35,6 +35,6 @@ void GroupStatePersistence::clear(const BulbId &id) { } char* GroupStatePersistence::buildFilename(const BulbId &id, char *buffer) { - uint32_t compactId = (id.deviceId << 24) | (id.deviceType << 8) | id.groupId; + uint32_t compactId = id.getCompactId(); return buffer + sprintf(buffer, "%s%x", FILE_PREFIX, compactId); } diff --git a/lib/Types/BulbId.cpp b/lib/Types/BulbId.cpp index 50802059..f01cce4a 100644 --- a/lib/Types/BulbId.cpp +++ b/lib/Types/BulbId.cpp @@ -34,3 +34,8 @@ bool BulbId::operator==(const BulbId &other) { && groupId == other.groupId && deviceType == other.deviceType; } + +uint32_t BulbId::getCompactId() const { + uint32_t id = (deviceId << 24) | (deviceType << 8) | groupId; + return id; +} \ No newline at end of file diff --git a/lib/Types/BulbId.h b/lib/Types/BulbId.h index faea8563..2aef270a 100644 --- a/lib/Types/BulbId.h +++ b/lib/Types/BulbId.h @@ -13,4 +13,5 @@ struct BulbId { BulbId(const uint16_t deviceId, const uint8_t groupId, const MiLightRemoteType deviceType); bool operator==(const BulbId& other); void operator=(const BulbId& other); + uint32_t getCompactId() const; }; \ No newline at end of file From eddda7f284914ce90aff8baf85602a6b63bd6d41 Mon Sep 17 00:00:00 2001 From: Christopher Mullins Date: Sun, 23 Jun 2019 10:08:44 -0700 Subject: [PATCH 06/17] Save deleted group IDs so that they can be processed --- lib/Settings/Settings.cpp | 10 ++++++++++ lib/Settings/Settings.h | 1 + 2 files changed, 11 insertions(+) diff --git a/lib/Settings/Settings.cpp b/lib/Settings/Settings.cpp index 486ff2b5..5339f99b 100644 --- a/lib/Settings/Settings.cpp +++ b/lib/Settings/Settings.cpp @@ -165,6 +165,13 @@ std::map::const_iterator Settings::findAlias(MiLightRemoteType d void Settings::parseGroupIdAliases(JsonObject json) { JsonObject aliases = json["group_id_aliases"]; + + // Save group IDs that were deleted so that they can be processed by discovery + // if necessary + for (auto it = groupIdAliases.begin(); it != groupIdAliases.end(); ++it) { + deletedGroupIdAliases[it->second.getCompactId()] = it->second; + } + groupIdAliases.clear(); for (JsonPair kv : aliases) { @@ -175,6 +182,9 @@ void Settings::parseGroupIdAliases(JsonObject json) { MiLightRemoteTypeHelpers::remoteTypeFromString(bulbIdProps[0].as()) }; groupIdAliases[kv.key().c_str()] = bulbId; + + // If added this round, do not mark as deleted. + deletedGroupIdAliases.erase(bulbId.getCompactId()); } } diff --git a/lib/Settings/Settings.h b/lib/Settings/Settings.h index d469ae3e..a25c8cdf 100644 --- a/lib/Settings/Settings.h +++ b/lib/Settings/Settings.h @@ -183,6 +183,7 @@ class Settings { String wifiStaticIPGateway; size_t packetRepeatsPerLoop; std::map groupIdAliases; + std::map deletedGroupIdAliases; String homeAssistantDiscoveryPrefix; protected: From 07e557f5af78d243d5daca0ddc0cd53885e48bc0 Mon Sep 17 00:00:00 2001 From: Christopher Mullins Date: Sun, 23 Jun 2019 10:09:19 -0700 Subject: [PATCH 07/17] Handle removing old discovery IDs --- lib/MQTT/HomeAssistantDiscoveryClient.cpp | 12 +++++++++++- lib/MQTT/HomeAssistantDiscoveryClient.h | 3 ++- src/main.cpp | 3 +++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/lib/MQTT/HomeAssistantDiscoveryClient.cpp b/lib/MQTT/HomeAssistantDiscoveryClient.cpp index e2e33272..20911df4 100644 --- a/lib/MQTT/HomeAssistantDiscoveryClient.cpp +++ b/lib/MQTT/HomeAssistantDiscoveryClient.cpp @@ -15,7 +15,17 @@ void HomeAssistantDiscoveryClient::sendDiscoverableDevices(const std::map& aliases) { +#ifdef MQTT_DEBUG + Serial.println(F("HomeAssistantDiscoveryClient: Removing discoverable devices...")); +#endif + + for (auto itr = aliases.begin(); itr != aliases.end(); ++itr) { + removeConfig(itr->second); + } +} + +void HomeAssistantDiscoveryClient::removeConfig(const BulbId& bulbId) { // Remove by publishing an empty message String topic = buildTopic(bulbId); mqttClient->send(topic.c_str(), "", true); diff --git a/lib/MQTT/HomeAssistantDiscoveryClient.h b/lib/MQTT/HomeAssistantDiscoveryClient.h index 9fb474ab..7171575f 100644 --- a/lib/MQTT/HomeAssistantDiscoveryClient.h +++ b/lib/MQTT/HomeAssistantDiscoveryClient.h @@ -9,9 +9,10 @@ class HomeAssistantDiscoveryClient { HomeAssistantDiscoveryClient(Settings& settings, MqttClient* mqttClient); void addConfig(const char* alias, const BulbId& bulbId); - void removeConfig(const char* alias, const BulbId& bulbId); + void removeConfig(const BulbId& bulbId); void sendDiscoverableDevices(const std::map& aliases); + void removeOldDevices(const std::map& aliases); private: Settings& settings; diff --git a/src/main.cpp b/src/main.cpp index ead912bf..18da71b0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -244,6 +244,9 @@ void applySettings() { if (settings.homeAssistantDiscoveryPrefix.length() > 0) { HomeAssistantDiscoveryClient discoveryClient(settings, mqttClient); discoveryClient.sendDiscoverableDevices(settings.groupIdAliases); + discoveryClient.removeOldDevices(settings.deletedGroupIdAliases); + + settings.deletedGroupIdAliases.clear(); } }); From 7dad7f3e84668b5f6b359d56374460a44399926a Mon Sep 17 00:00:00 2001 From: Christopher Mullins Date: Sun, 23 Jun 2019 10:09:38 -0700 Subject: [PATCH 08/17] Fix name generator --- lib/MQTT/HomeAssistantDiscoveryClient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/MQTT/HomeAssistantDiscoveryClient.cpp b/lib/MQTT/HomeAssistantDiscoveryClient.cpp index 20911df4..7bf8cf65 100644 --- a/lib/MQTT/HomeAssistantDiscoveryClient.cpp +++ b/lib/MQTT/HomeAssistantDiscoveryClient.cpp @@ -117,7 +117,7 @@ String HomeAssistantDiscoveryClient::buildTopic(const BulbId& bulbId) { topic += "light/"; // Use a static ID that doesn't depend on configuration. - topic += "milight_hub_" + (ESP.getChipId()); + topic += "milight_hub_" + String(ESP.getChipId()); // make the object ID based on the actual parameters rather than the alias. topic += "/"; From 8ae163dbc146d032ba6449008ef7bfe6eacd9647 Mon Sep 17 00:00:00 2001 From: Christopher Mullins Date: Sun, 23 Jun 2019 10:09:48 -0700 Subject: [PATCH 09/17] Send longer messages in chunks --- lib/MQTT/MqttClient.cpp | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/lib/MQTT/MqttClient.cpp b/lib/MQTT/MqttClient.cpp index 15a5b6c2..cd8393fb 100644 --- a/lib/MQTT/MqttClient.cpp +++ b/lib/MQTT/MqttClient.cpp @@ -157,7 +157,29 @@ void MqttClient::subscribe() { } void MqttClient::send(const char* topic, const char* message, const bool retain) { - mqttClient.publish(topic, message, retain); + size_t len = strlen(message); + size_t topicLen = strlen(topic); + + if ((topicLen + len + 10) < MQTT_MAX_PACKET_SIZE ) { + mqttClient.publish(topic, message, retain); + } else { + const uint8_t* messageBuffer = reinterpret_cast(message); + mqttClient.beginPublish(topic, len, retain); + +#ifdef MQTT_DEBUG + Serial.printf_P(PSTR("Printing message in parts because it's too large for the packet buffer (%d bytes)"), len); +#endif + + for (size_t i = 0; i < len; i += MQTT_PACKET_CHUNK_SIZE) { + size_t toWrite = std::min(static_cast(MQTT_PACKET_CHUNK_SIZE), len - i); + mqttClient.write(messageBuffer+i, toWrite); +#ifdef MQTT_DEBUG + Serial.printf_P(PSTR(" Wrote %d bytes\n"), toWrite); +#endif + } + + mqttClient.endPublish(); + } } void MqttClient::publish( From aaa572b6762e2572c751dce547073a3c6fd3d767 Mon Sep 17 00:00:00 2001 From: Christopher Mullins Date: Sun, 23 Jun 2019 10:10:02 -0700 Subject: [PATCH 10/17] Add comment --- platformio.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/platformio.ini b/platformio.ini index 2c99a02e..15db9450 100644 --- a/platformio.ini +++ b/platformio.ini @@ -30,6 +30,7 @@ test_ignore = remote upload_speed = 460800 build_flags = !python .get_version.py + # For compatibility with WebSockets 2.1.4 and v2.4 of the Arduino SDK -D USING_AXTLS -D MQTT_MAX_PACKET_SIZE=250 -D HTTP_UPLOAD_BUFLEN=128 From b10d676967962b50fc4a7c5f84fffc2d9102b96f Mon Sep 17 00:00:00 2001 From: Christopher Mullins Date: Sun, 23 Jun 2019 10:10:25 -0700 Subject: [PATCH 11/17] Conditionally raise error --- test/remote/lib/mqtt_client.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/remote/lib/mqtt_client.rb b/test/remote/lib/mqtt_client.rb index e428f6e4..e58a2425 100644 --- a/test/remote/lib/mqtt_client.rb +++ b/test/remote/lib/mqtt_client.rb @@ -70,7 +70,7 @@ def on_id_message(path, id_params, timeout, &block) end end - def on_message(topic, timeout = 10, &block) + def on_message(topic, timeout = 10, raise_error = true, &block) @listen_threads << Thread.new do begin Timeout.timeout(timeout) do @@ -81,7 +81,7 @@ def on_message(topic, timeout = 10, &block) end rescue Timeout::Error => e puts "Timed out listening for message on: #{topic}" - raise e + raise e if raise_error rescue BreakListenLoopError end end From e51d19bb3874f135d542ccba05270953db45f6a0 Mon Sep 17 00:00:00 2001 From: Christopher Mullins Date: Sun, 23 Jun 2019 10:10:39 -0700 Subject: [PATCH 12/17] Add support for retained messages in test client --- test/remote/lib/mqtt_client.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/remote/lib/mqtt_client.rb b/test/remote/lib/mqtt_client.rb index e58a2425..134df2f2 100644 --- a/test/remote/lib/mqtt_client.rb +++ b/test/remote/lib/mqtt_client.rb @@ -87,8 +87,10 @@ def on_message(topic, timeout = 10, raise_error = true, &block) end end - def publish(topic, state = {}) - @client.publish(topic, state.to_json) + def publish(topic, state = {}, retain = false) + state = state.to_json unless state.is_a?(String) + + @client.publish(topic, state, retain) end def patch_state(id_params, state = {}) From db528afb0c5cd10eaccfaba34a58759594b6d7ac Mon Sep 17 00:00:00 2001 From: Christopher Mullins Date: Sun, 23 Jun 2019 10:10:55 -0700 Subject: [PATCH 13/17] Fix, spruce up tests --- test/remote/spec/discovery_spec.rb | 84 +++++++++++++++++++++++------- 1 file changed, 66 insertions(+), 18 deletions(-) diff --git a/test/remote/spec/discovery_spec.rb b/test/remote/spec/discovery_spec.rb index c8b00737..81094dd7 100644 --- a/test/remote/spec/discovery_spec.rb +++ b/test/remote/spec/discovery_spec.rb @@ -4,12 +4,27 @@ before(:all) do @client = ApiClient.new(ENV.fetch('ESPMH_HOSTNAME'), ENV.fetch('ESPMH_TEST_DEVICE_ID_BASE')) @client.upload_json('/settings', 'settings.json') + + @test_id = 1 + @topic_prefix = mqtt_topic_prefix() + @discovery_prefix = "#{@topic_prefix}discovery/" + + @mqtt_client = create_mqtt_client() + end + + after(:all) do + # Clean up any leftover cruft + @mqtt_client.on_message("#{@discovery_prefix}#", 1, false) do |topic, message| + if message.length > 0 + @mqtt_client.publish(topic, '', true) + end + false + end + @mqtt_client.wait_for_listeners end before(:each) do mqtt_params = mqtt_parameters() - @topic_prefix = mqtt_topic_prefix() - @discovery_prefix = "#{@topic_prefix}/discovery" @client.put( '/settings', @@ -21,9 +36,8 @@ type: 'rgb_cct', group_id: 1 } - @discovery_suffix = "#{@id_params[:type]}_#{sprintf("%x", @id_params[:id])}_#{@id_params[:group_id]}" - - @mqtt_client = create_mqtt_client() + @discovery_suffix = "#{@id_params[:type]}_#{sprintf("0x%04x", @id_params[:id])}_#{@id_params[:group_id]}/config" + @test_discovery_prefix = "#{@discovery_prefix}#{@id_params[:id]}/" end context 'when not configured' do @@ -42,45 +56,46 @@ it 'should send discovery messages' do saw_message = false - @mqtt_client.on_message("#{@discovery_prefix}/light/+/#{@discovery_suffix}") do |topic, message| + @mqtt_client.on_message("#{@test_discovery_prefix}light/+/#{@discovery_suffix}") do |topic, message| saw_message = true end @client.patch_settings( - home_assistant_discovery_prefix: @discovery_prefix, + home_assistant_discovery_prefix: @test_discovery_prefix, group_id_aliases: { 'test_group' => [@id_params[:type], @id_params[:id], @id_params[:group_id]] } ) - expect(saw_message).to be_true + @mqtt_client.wait_for_listeners + + expect(saw_message).to be(true) end it 'config should have expected keys' do saw_message = false config = nil - @mqtt_client.on_message("#{@discovery_prefix}/light/+/#{@discovery_suffix}") do |topic, message| + @mqtt_client.on_message("#{@test_discovery_prefix}light/+/#{@discovery_suffix}") do |topic, message| config = JSON.parse(message) saw_message = true end @client.patch_settings( - home_assistant_discovery_prefix: @discovery_prefix, + home_assistant_discovery_prefix: @test_discovery_prefix, group_id_aliases: { 'test_group' => [@id_params[:type], @id_params[:id], @id_params[:group_id]] } ) - expect(saw_message).to be_true + @mqtt_client.wait_for_listeners + + expect(saw_message).to be(true) expected_keys = %w( schema name command_topic state_topic - availability_topic - payload_available - payload_not_available brightness rgb color_temp @@ -94,16 +109,16 @@ seen_config = false seen_blank_message = false - @mqtt_client.on_message("#{@discovery_prefix}/light/+/#{@discovery_suffix}") do |topic, message| - seen_config = message.length > 0 - seen_blank_message = message.empty? + @mqtt_client.on_message("#{@test_discovery_prefix}light/+/#{@discovery_suffix}") do |topic, message| + seen_config = seen_config || message.length > 0 + seen_blank_message = seen_blank_message || message.length == 0 seen_config && seen_blank_message end # This should create the device @client.patch_settings( - home_assistant_discovery_prefix: @discovery_prefix, + home_assistant_discovery_prefix: @test_discovery_prefix, group_id_aliases: { 'test_group' => [@id_params[:type], @id_params[:id], @id_params[:group_id]] } @@ -113,6 +128,39 @@ @client.patch_settings( group_id_aliases: { } ) + + @mqtt_client.wait_for_listeners + + expect(seen_config).to be(true) + expect(seen_blank_message).to be(true), "should see deletion message" + end + + it 'should configure devices with an availability topic if client status is configured' do + expected_keys = %w( + availability_topic + payload_available + payload_not_available + ) + config = nil + + @mqtt_client.on_message("#{@test_discovery_prefix}light/+/#{@discovery_suffix}") do |topic, message| + config = JSON.parse(message) + (expected_keys - config.keys).empty? + end + + # This should create the device + @client.patch_settings( + home_assistant_discovery_prefix: @test_discovery_prefix, + group_id_aliases: { + 'test_group' => [@id_params[:type], @id_params[:id], @id_params[:group_id]] + }, + mqtt_client_status_topic: "#{@topic_prefix}status", + simple_mqtt_client_status: true + ) + + @mqtt_client.wait_for_listeners + + expect(config.keys).to include(*expected_keys) end end end \ No newline at end of file From 0aefdb98393cf1b2eb00c6da266e7f8dc7f1042a Mon Sep 17 00:00:00 2001 From: Christopher Mullins Date: Sun, 23 Jun 2019 11:32:49 -0700 Subject: [PATCH 14/17] DRY: add helper method to generate hex string for device ID --- lib/MQTT/HomeAssistantDiscoveryClient.cpp | 9 +++++---- lib/Types/BulbId.cpp | 6 ++++++ lib/Types/BulbId.h | 2 ++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/MQTT/HomeAssistantDiscoveryClient.cpp b/lib/MQTT/HomeAssistantDiscoveryClient.cpp index 7bf8cf65..f230852b 100644 --- a/lib/MQTT/HomeAssistantDiscoveryClient.cpp +++ b/lib/MQTT/HomeAssistantDiscoveryClient.cpp @@ -122,8 +122,8 @@ String HomeAssistantDiscoveryClient::buildTopic(const BulbId& bulbId) { // make the object ID based on the actual parameters rather than the alias. topic += "/"; topic += MiLightRemoteTypeHelpers::remoteTypeToString(bulbId.deviceType); - topic += "_0x"; - topic += String(bulbId.deviceId, HEX); + topic += "_"; + topic += bulbId.getHexDeviceId(); topic += "_"; topic += bulbId.groupId; topic += "/config"; @@ -133,10 +133,11 @@ String HomeAssistantDiscoveryClient::buildTopic(const BulbId& bulbId) { String HomeAssistantDiscoveryClient::bindTopicVariables(const String& topic, const char* alias, const BulbId& bulbId) { String boundTopic = topic; + String hexDeviceId = bulbId.getHexDeviceId(); boundTopic.replace(":device_alias", alias); - boundTopic.replace(":device_id", String("0x") + String(bulbId.deviceId, HEX)); - boundTopic.replace(":hex_device_id", String("0x") + String(bulbId.deviceId, HEX)); + boundTopic.replace(":device_id", hexDeviceId); + boundTopic.replace(":hex_device_id", hexDeviceId); boundTopic.replace(":dec_device_id", String(bulbId.deviceId)); boundTopic.replace(":device_type", MiLightRemoteTypeHelpers::remoteTypeToString(bulbId.deviceType)); boundTopic.replace(":group_id", String(bulbId.groupId)); diff --git a/lib/Types/BulbId.cpp b/lib/Types/BulbId.cpp index f01cce4a..e48425ed 100644 --- a/lib/Types/BulbId.cpp +++ b/lib/Types/BulbId.cpp @@ -38,4 +38,10 @@ bool BulbId::operator==(const BulbId &other) { uint32_t BulbId::getCompactId() const { uint32_t id = (deviceId << 24) | (deviceType << 8) | groupId; return id; +} + +String BulbId::getHexDeviceId() const { + char hexDeviceId[7]; + sprintf_P(hexDeviceId, PSTR("0x%X"), deviceId); + return hexDeviceId; } \ No newline at end of file diff --git a/lib/Types/BulbId.h b/lib/Types/BulbId.h index 2aef270a..91ded34d 100644 --- a/lib/Types/BulbId.h +++ b/lib/Types/BulbId.h @@ -13,5 +13,7 @@ struct BulbId { BulbId(const uint16_t deviceId, const uint8_t groupId, const MiLightRemoteType deviceType); bool operator==(const BulbId& other); void operator=(const BulbId& other); + uint32_t getCompactId() const; + String getHexDeviceId() const; }; \ No newline at end of file From 220508012b29348c3b3426dc4f194ee2175adc67 Mon Sep 17 00:00:00 2001 From: Christopher Mullins Date: Sun, 23 Jun 2019 11:33:35 -0700 Subject: [PATCH 15/17] DRY: expose helper method in MqttClient to bind variables to topic string, use that instead of repeated logic --- lib/MQTT/HomeAssistantDiscoveryClient.cpp | 4 +-- lib/MQTT/MqttClient.cpp | 34 ++++++++++------------- lib/MQTT/MqttClient.h | 9 ++---- 3 files changed, 19 insertions(+), 28 deletions(-) diff --git a/lib/MQTT/HomeAssistantDiscoveryClient.cpp b/lib/MQTT/HomeAssistantDiscoveryClient.cpp index f230852b..2f93e3eb 100644 --- a/lib/MQTT/HomeAssistantDiscoveryClient.cpp +++ b/lib/MQTT/HomeAssistantDiscoveryClient.cpp @@ -37,8 +37,8 @@ void HomeAssistantDiscoveryClient::addConfig(const char* alias, const BulbId& bu config[F("schema")] = F("json"); config[F("name")] = alias; - config[F("command_topic")] = bindTopicVariables(settings.mqttTopicPattern, alias, bulbId); - config[F("state_topic")] = bindTopicVariables(settings.mqttStateTopicPattern, alias, bulbId); + config[F("command_topic")] = mqttClient->bindTopicString(settings.mqttTopicPattern, bulbId); + config[F("state_topic")] = mqttClient->bindTopicString(settings.mqttStateTopicPattern, bulbId); // HomeAssistant only supports simple client availability if (settings.mqttClientStatusTopic.length() > 0 && settings.simpleMqttClientStatus) { diff --git a/lib/MQTT/MqttClient.cpp b/lib/MQTT/MqttClient.cpp index cd8393fb..0e3fffd1 100644 --- a/lib/MQTT/MqttClient.cpp +++ b/lib/MQTT/MqttClient.cpp @@ -194,8 +194,8 @@ void MqttClient::publish( return; } - String topic = _topic; - MqttClient::bindTopicString(topic, remoteConfig, deviceId, groupId); + BulbId bulbId(deviceId, groupId, remoteConfig.type); + String topic = bindTopicString(_topic, bulbId); #ifdef MQTT_DEBUG printf("MqttClient - publishing update to %s\n", topic.c_str()); @@ -274,28 +274,24 @@ void MqttClient::publishCallback(char* topic, byte* payload, int length) { milightClient->update(obj); } -inline void MqttClient::bindTopicString( - String& topicPattern, - const MiLightRemoteConfig& remoteConfig, - const uint16_t deviceId, - const uint16_t groupId -) { - String deviceIdHex = String(deviceId, 16); - deviceIdHex.toUpperCase(); - deviceIdHex = String("0x") + deviceIdHex; +String MqttClient::bindTopicString(const String& topicPattern, const BulbId& bulbId) { + String boundTopic = topicPattern; + String deviceIdHex = bulbId.getHexDeviceId(); - topicPattern.replace(":device_id", deviceIdHex); - topicPattern.replace(":hex_device_id", deviceIdHex); - topicPattern.replace(":dec_device_id", String(deviceId)); - topicPattern.replace(":group_id", String(groupId)); - topicPattern.replace(":device_type", remoteConfig.name); + boundTopic.replace(":device_id", deviceIdHex); + boundTopic.replace(":hex_device_id", deviceIdHex); + boundTopic.replace(":dec_device_id", String(bulbId.deviceId)); + boundTopic.replace(":group_id", String(bulbId.groupId)); + boundTopic.replace(":device_type", MiLightRemoteTypeHelpers::remoteTypeToString(bulbId.deviceType)); - auto it = settings.findAlias(remoteConfig.type, deviceId, groupId); + auto it = settings.findAlias(bulbId.deviceType, bulbId.deviceId, bulbId.groupId); if (it != settings.groupIdAliases.end()) { - topicPattern.replace(":device_alias", it->first); + boundTopic.replace(":device_alias", it->first); } else { - topicPattern.replace(":device_alias", "__unnamed_group"); + boundTopic.replace(":device_alias", "__unnamed_group"); } + + return boundTopic; } String MqttClient::generateConnectionStatusMessage(const char* connectionStatus) { diff --git a/lib/MQTT/MqttClient.h b/lib/MQTT/MqttClient.h index f907b452..dc601c4b 100644 --- a/lib/MQTT/MqttClient.h +++ b/lib/MQTT/MqttClient.h @@ -30,6 +30,8 @@ class MqttClient { void send(const char* topic, const char* message, const bool retain = false); void onConnect(OnConnectFn fn); + String bindTopicString(const String& topicPattern, const BulbId& bulbId); + private: WiFiClient tcpClient; PubSubClient mqttClient; @@ -53,13 +55,6 @@ class MqttClient { const bool retain = false ); - inline void bindTopicString( - String& topicPattern, - const MiLightRemoteConfig& remoteConfig, - const uint16_t deviceId, - const uint16_t groupId - ); - String generateConnectionStatusMessage(const char* status); }; From 79a88ff7ec7040fba283f209e04c21e529e88f9a Mon Sep 17 00:00:00 2001 From: Christopher Mullins Date: Sun, 23 Jun 2019 11:33:45 -0700 Subject: [PATCH 16/17] Fix compiler warning --- lib/MiLight/PacketSender.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/MiLight/PacketSender.cpp b/lib/MiLight/PacketSender.cpp index 5f3d162e..8067ebd8 100644 --- a/lib/MiLight/PacketSender.cpp +++ b/lib/MiLight/PacketSender.cpp @@ -109,7 +109,7 @@ void PacketSender::updateResendCount() { if (signedResends < static_cast(settings.packetRepeatMinimum)) { signedResends = settings.packetRepeatMinimum; - } else if (signedResends > settings.packetRepeats) { + } else if (signedResends > static_cast(settings.packetRepeats)) { signedResends = settings.packetRepeats; } From 5924422f8292a07ee5ada844c12607d2f5a5ddae Mon Sep 17 00:00:00 2001 From: Christopher Mullins Date: Sun, 23 Jun 2019 11:33:57 -0700 Subject: [PATCH 17/17] Add sleep -- this was working without before because of debug logging --- test/remote/spec/mqtt_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/test/remote/spec/mqtt_spec.rb b/test/remote/spec/mqtt_spec.rb index a5ebc843..955d84c2 100644 --- a/test/remote/spec/mqtt_spec.rb +++ b/test/remote/spec/mqtt_spec.rb @@ -182,6 +182,7 @@ (1..num_updates).each do |i| @mqtt_client.patch_state(@id_params, level: i) + sleep 0.1 end @mqtt_client.wait_for_listeners