Git Product home page Git Product logo

Comments (5)

Mixiaoxiao avatar Mixiaoxiao commented on May 23, 2024

Paste your code here.

from arduino-homekit-esp8266.

wahidsa avatar wahidsa commented on May 23, 2024

the my_accessory.c

`/*

  • my_accessory.c
  • Define the accessory in C language using the Macro in characteristics.h
  • Created on: 2020-05-15
  •  Author: Mixiaoxiao (Wang Bin)
    

*/

#include <Arduino.h>
#include <homekit/homekit.h>
#include <homekit/characteristics.h>

#define PIN_LED 2

int led_bri = 100; //[0, 100]
bool led_power = false; //true or flase

homekit_value_t led_on_get() {
return HOMEKIT_BOOL(led_power);
}

void led_on_set(homekit_value_t value) {
if (value.format != homekit_format_bool) {
printf("Invalid on-value format: %d\n", value.format);
return;
}
led_power = value.bool_value;
if (led_power) {
if (led_bri < 1) {
led_bri = 100;
}
}
led_update();
}

homekit_value_t light_bri_get() {
return HOMEKIT_INT(led_bri);
}

void led_bri_set(homekit_value_t value) {
if (value.format != homekit_format_int) {
return;
}
led_bri = value.int_value;
led_update();
}

void my_accessory_identify(homekit_value_t _value) {
printf("accessory identify\n");
}

// Switch (HAP section 8.38)
// required: ON
// optional: NAME

// format: bool; HAP section 9.70; write the .setter function to get the switch-event sent from iOS Home APP.
homekit_characteristic_t led_on = HOMEKIT_CHARACTERISTIC_(ON, false,
//.callback=HOMEKIT_CHARACTERISTIC_CALLBACK(switch_on_callback),
.getter = led_on_get,
.setter = led_on_set
);

// format: string; HAP section 9.62; max length 64
homekit_characteristic_t cha_name = HOMEKIT_CHARACTERISTIC_(NAME, "Temperature");

homekit_accessory_t accessories[] = {
HOMEKIT_ACCESSORY(.id=1,
.category=homekit_accessory_category_lightbulb,
.services=(homekit_service_t
[]) {
HOMEKIT_SERVICE(ACCESSORY_INFORMATION, .characteristics=(homekit_characteristic_t*[]) {
HOMEKIT_CHARACTERISTIC(NAME, "Temperature"),
HOMEKIT_CHARACTERISTIC(MANUFACTURER, "Wahid"),
HOMEKIT_CHARACTERISTIC(SERIAL_NUMBER, "0000457"),
HOMEKIT_CHARACTERISTIC(MODEL, "AirCondition"),
HOMEKIT_CHARACTERISTIC(FIRMWARE_REVISION, "1.0"),
HOMEKIT_CHARACTERISTIC(IDENTIFY, my_accessory_identify),
NULL
}),
HOMEKIT_SERVICE(LIGHTBULB, .primary=true,
.characteristics=(homekit_characteristic_t*[]){
HOMEKIT_CHARACTERISTIC(NAME, "Led"),
&led_on,
// &cha_name,
HOMEKIT_CHARACTERISTIC(BRIGHTNESS, 100,
.getter=light_bri_get,
.setter=led_bri_set
),
NULL
}),
NULL
}),
NULL
};

void led_update() {
if (led_power) {
int pwm = PWMRANGE - (int) (led_bri * 1.0 * PWMRANGE / 100.0 + 0.5f);
analogWrite(PIN_LED, pwm);
printf("ON %3d (pwm: %4d of %d)\n", led_bri, pwm, PWMRANGE);
} else {
printf("OFF\n");
digitalWrite(PIN_LED, HIGH);
}
}

void occupancy_toggle() {

// const uint8_t state = occupancy_detected.value.uint8_value;
// occupancy_detected.value = HOMEKIT_UINT8((!state) ? 1 : 0);
// homekit_characteristic_notify(&occupancy_detected, occupancy_detected.value);
}

void led_toggle() {
led_on.value.bool_value = !led_on.value.bool_value;
led_on.setter(led_on.value);
homekit_characteristic_notify(&led_on, led_on.value);
}

homekit_server_config_t config = {
.accessories = accessories,
.password = "111-11-111"
};`

from arduino-homekit-esp8266.

wahidsa avatar wahidsa commented on May 23, 2024

the main code "led.homekit.ino"

`#include <Arduino.h>
#include <arduino_homekit_server.h>
#include "ButtonDebounce.h"
#include "ButtonHandler.h"
/*#include <IRsend.h>
int irLed = 14; //D5 iR LED
IRsend irsend (irLed);

uint16_t OFF[171] = {6030, 1086, 1178, 436, 1178, 438, 460, 1148, 456, 1212, 458, 1148, 456, 1146, 1178, 440, 456, 1210, 456, 1150, 456, 1150, 458, 1148, 456, 1208, 1178, 436, 1202, 416, 458, 1146, 460, 1210, 458, 1148, 458, 1150, 456, 1150, 456, 1210, 456, 1144, 1176, 440, 460, 1150, 454, 1206, 1178, 438, 1204, 414, 456, 1150, 456, 1210, 456, 1148, 458, 1148, 458, 1146, 458, 1210, 456, 1152, 456, 1148, 456, 1148, 460, 1208, 456, 1144, 1206, 414, 458, 1148, 456, 1208, 1204, 414, 456, 1150, 456, 1150, 454, 1212, 456, 1150, 456, 1150, 456, 1146, 458, 1214, 452, 1150, 458, 1148, 456, 1150, 456, 1212, 458, 1144, 1174, 442, 458, 1148, 456, 1208, 1176, 442, 458, 1150, 454, 1152, 454, 1210, 458, 1148, 456, 1150, 456, 1148, 458, 1210, 456, 1150, 456, 1150, 456, 1150, 456, 1210, 458, 1144, 1174, 444, 456, 1152, 454, 1206, 1174, 444, 458, 1150, 454, 1152, 452, 1208, 1174, 444, 456, 1150, 458, 1144, 1200, 476, 1172, 442, 1202, 412, 1174, 440, 1200, 422, 1196}; // UNKNOWN AE963374
uint16_t cold20[171] = {5990, 1130, 372, 1234, 372, 1228, 1144, 470, 1146, 534, 374, 1232, 374, 1228, 1144, 474, 374, 1286, 1146, 470, 1146, 472, 374, 1230, 376, 1314, 1120, 468, 1146, 474, 374, 1232, 372, 1296, 372, 1232, 374, 1232, 374, 1234, 374, 1292, 374, 1226, 1148, 472, 374, 1230, 374, 1288, 1146, 468, 1146, 474, 374, 1232, 374, 1292, 376, 1256, 348, 1234, 372, 1232, 372, 1294, 374, 1232, 374, 1232, 372, 1234, 374, 1292, 372, 1228, 1144, 474, 374, 1234, 372, 1288, 1146, 474, 374, 1232, 374, 1234, 372, 1294, 372, 1232, 374, 1232, 374, 1230, 376, 1292, 374, 1232, 374, 1230, 376, 1230, 376, 1292, 376, 1228, 1146, 472, 374, 1232, 374, 1288, 1146, 472, 374, 1232, 374, 1232, 372, 1292, 376, 1230, 374, 1232, 374, 1234, 372, 1292, 374, 1232, 374, 1232, 372, 1230, 376, 1294, 372, 1228, 1146, 474, 374, 1256, 350, 1288, 1146, 474, 374, 1232, 372, 1232, 374, 1290, 1144, 474, 374, 1228, 1146, 472, 374, 1294, 374, 1256, 352, 1230, 374, 1234, 372, 1232, 1144}; // UNKNOWN 1621CDD4
uint16_t cold21[171] = {6042, 1080, 430, 1174, 430, 1174, 1160, 480, 1138, 542, 404, 1176, 430, 1172, 1164, 482, 404, 1236, 432, 1176, 430, 1174, 432, 1176, 430, 1232, 1164, 478, 1138, 480, 404, 1174, 430, 1234, 1164, 482, 402, 1174, 432, 1176, 432, 1236, 430, 1174, 1162, 482, 404, 1176, 430, 1232, 1166, 478, 1138, 482, 428, 1148, 432, 1236, 430, 1174, 432, 1174, 432, 1176, 430, 1236, 430, 1176, 428, 1176, 430, 1176, 430, 1238, 430, 1170, 1164, 484, 404, 1176, 430, 1234, 1164, 482, 402, 1176, 428, 1178, 428, 1238, 430, 1176, 430, 1174, 430, 1178, 430, 1236, 430, 1176, 430, 1174, 430, 1172, 434, 1236, 430, 1172, 1166, 480, 428, 1152, 428, 1232, 1192, 456, 430, 1148, 454, 1150, 432, 1238, 430, 1174, 456, 1150, 430, 1176, 454, 1210, 434, 1178, 452, 1150, 454, 1150, 454, 1212, 456, 1148, 1194, 450, 430, 1148, 456, 1206, 1196, 450, 458, 1122, 482, 1122, 456, 1204, 1198, 446, 1170, 450, 458, 1122, 484, 1182, 484, 1122, 486, 1120, 486, 1122, 482, 1124, 1194}; // UNKNOWN 191BEFEC
uint16_t cold22[171] = {5984, 1136, 428, 1176, 430, 1172, 1162, 456, 1158, 548, 402, 1178, 430, 1170, 1134, 488, 428, 1238, 430, 1176, 428, 1178, 430, 1178, 426, 1236, 1134, 508, 1134, 486, 402, 1174, 430, 1238, 428, 1172, 1162, 462, 426, 1174, 432, 1240, 428, 1172, 1162, 484, 402, 1176, 428, 1236, 1158, 458, 1130, 514, 402, 1178, 428, 1236, 430, 1178, 428, 1176, 430, 1176, 430, 1240, 428, 1176, 430, 1178, 428, 1176, 430, 1238, 430, 1174, 1158, 462, 428, 1176, 430, 1234, 1160, 460, 428, 1178, 428, 1176, 428, 1240, 428, 1180, 428, 1174, 430, 1176, 430, 1238, 430, 1178, 428, 1178, 430, 1176, 428, 1238, 430, 1172, 1136, 512, 402, 1178, 428, 1234, 1136, 508, 402, 1176, 430, 1176, 430, 1234, 1164, 458, 426, 1178, 428, 1178, 428, 1240, 428, 1178, 428, 1178, 428, 1178, 428, 1238, 430, 1172, 1168, 478, 402, 1178, 428, 1232, 1166, 480, 402, 1178, 428, 1178, 454, 1214, 428, 1178, 454, 1148, 1164, 482, 426, 1210, 1140, 506, 428, 1152, 428, 1176, 456, 1150, 1166}; // UNKNOWN 483AC1E0
uint16_t cold23[171] = {6040, 1080, 430, 1174, 456, 1146, 1160, 480, 1136, 544, 404, 1176, 428, 1172, 1164, 480, 404, 1236, 430, 1178, 428, 1176, 430, 1176, 430, 1232, 1164, 478, 1140, 480, 428, 1150, 430, 1232, 1168, 476, 1140, 480, 430, 1150, 428, 1238, 430, 1172, 1162, 484, 406, 1174, 428, 1234, 1166, 476, 1168, 452, 430, 1150, 454, 1212, 430, 1176, 430, 1174, 432, 1176, 430, 1236, 430, 1178, 428, 1178, 430, 1176, 430, 1236, 430, 1174, 1190, 454, 430, 1148, 456, 1208, 1164, 480, 430, 1148, 454, 1150, 430, 1236, 432, 1176, 454, 1150, 456, 1150, 456, 1212, 452, 1154, 456, 1152, 454, 1150, 456, 1212, 456, 1146, 1194, 452, 456, 1122, 458, 1204, 1196, 450, 458, 1120, 484, 1122, 458, 1210, 482, 1124, 456, 1150, 456, 1148, 458, 1210, 458, 1148, 456, 1150, 456, 1148, 458, 1208, 484, 1118, 1194, 452, 460, 1120, 484, 1176, 1194, 452, 458, 1122, 484, 1120, 486, 1178, 1196, 450, 458, 1116, 1194, 452, 458, 1182, 484, 1120, 486, 1118, 486, 1122, 484, 1120, 1196}; // UNKNOWN F6C406D4
uint16_t cold24[171] = {6040, 1080, 484, 1120, 486, 1114, 1196, 446, 1168, 514, 458, 1120, 486, 1116, 1194, 452, 458, 1182, 486, 1120, 486, 1120, 486, 1120, 486, 1176, 1194, 448, 1168, 452, 460, 1118, 486, 1182, 484, 1120, 486, 1118, 1192, 452, 460, 1180, 486, 1116, 1192, 452, 460, 1120, 486, 1176, 1194, 448, 1166, 454, 458, 1120, 486, 1182, 486, 1120, 486, 1122, 484, 1120, 486, 1182, 484, 1120, 486, 1122, 484, 1120, 486, 1180, 486, 1118, 1192, 452, 458, 1118, 488, 1174, 1196, 452, 460, 1118, 486, 1120, 486, 1180, 488, 1120, 486, 1120, 486, 1120, 486, 1182, 486, 1118, 486, 1120, 486, 1120, 486, 1180, 484, 1116, 1192, 454, 458, 1120, 484, 1178, 1192, 454, 458, 1120, 486, 1120, 486, 1182, 486, 1118, 488, 1122, 484, 1120, 486, 1182, 486, 1122, 484, 1120, 486, 1122, 484, 1184, 484, 1116, 1192, 454, 456, 1124, 484, 1178, 1192, 454, 456, 1124, 482, 1122, 484, 1182, 486, 1118, 1192, 450, 1164, 456, 454, 1186, 484, 1122, 484, 1122, 484, 1122, 484, 1124, 1190}; // UNKNOWN 85B2983C
uint16_t cold25[171] = {6042, 1078, 430, 1176, 428, 1174, 1162, 478, 1168, 512, 430, 1152, 428, 1172, 1164, 480, 430, 1210, 430, 1176, 430, 1178, 428, 1176, 430, 1232, 1162, 480, 1140, 480, 428, 1150, 430, 1232, 1164, 484, 402, 1174, 1136, 506, 404, 1238, 428, 1172, 1164, 482, 402, 1176, 430, 1234, 1166, 476, 1136, 484, 404, 1176, 430, 1238, 428, 1176, 430, 1176, 430, 1178, 428, 1238, 428, 1178, 428, 1176, 430, 1176, 430, 1238, 428, 1170, 1164, 484, 402, 1174, 432, 1234, 1164, 482, 402, 1178, 428, 1176, 430, 1238, 428, 1180, 428, 1176, 432, 1174, 430, 1238, 430, 1174, 432, 1176, 428, 1178, 428, 1234, 432, 1172, 1164, 482, 430, 1148, 430, 1232, 1166, 480, 430, 1148, 430, 1174, 456, 1212, 430, 1178, 428, 1176, 456, 1150, 454, 1216, 454, 1150, 430, 1174, 454, 1152, 456, 1212, 456, 1146, 1194, 452, 440, 1138, 458, 1206, 1192, 452, 458, 1122, 456, 1150, 456, 1208, 1194, 446, 1168, 446, 1168, 450, 458, 1182, 484, 1124, 456, 1150, 458, 1148, 482, 1124, 1194}; // UNKNOWN 7F08A680
uint16_t hot23[171] = {6038, 1082, 484, 1122, 484, 1116, 1192, 448, 1164, 510, 1166, 450, 1164, 454, 458, 1120, 486, 1182, 486, 1120, 486, 1118, 488, 1118, 486, 1180, 1192, 448, 1166, 452, 458, 1120, 486, 1176, 1194, 448, 1168, 452, 458, 1120, 488, 1180, 486, 1116, 1192, 452, 460, 1118, 486, 1176, 1196, 446, 1168, 452, 458, 1120, 486, 1180, 486, 1122, 484, 1120, 488, 1118, 486, 1180, 488, 1120, 488, 1118, 486, 1118, 488, 1182, 482, 1118, 1196, 450, 460, 1118, 486, 1178, 1198, 450, 460, 1120, 484, 1120, 484, 1182, 484, 1124, 484, 1122, 484, 1122, 484, 1182, 486, 1120, 484, 1122, 486, 1120, 486, 1182, 484, 1116, 1196, 452, 458, 1118, 488, 1178, 1194, 450, 460, 1120, 484, 1120, 486, 1178, 1194, 452, 458, 1120, 484, 1120, 484, 1182, 486, 1118, 486, 1120, 486, 1120, 484, 1184, 486, 1114, 1194, 452, 460, 1118, 484, 1178, 1192, 452, 458, 1122, 484, 1118, 486, 1176, 1196, 452, 458, 1116, 1194, 452, 458, 1184, 484, 1120, 486, 1120, 486, 1120, 484, 1124, 1192}; // UNKNOWN E2A64114
uint16_t hot25[171] = {6038, 1082, 484, 1120, 486, 1116, 1194, 450, 1164, 512, 1164, 450, 1166, 454, 458, 1120, 486, 1182, 484, 1120, 484, 1122, 486, 1118, 488, 1176, 1194, 450, 1164, 454, 460, 1120, 484, 1176, 1194, 454, 458, 1116, 1192, 454, 460, 1180, 486, 1116, 1194, 452, 458, 1120, 486, 1178, 1190, 450, 1164, 454, 460, 1118, 488, 1180, 488, 1118, 488, 1118, 486, 1120, 488, 1180, 486, 1118, 488, 1120, 486, 1118, 488, 1180, 486, 1114, 1194, 452, 458, 1120, 486, 1176, 1194, 454, 458, 1120, 486, 1120, 484, 1184, 484, 1120, 486, 1120, 484, 1122, 486, 1180, 486, 1120, 484, 1122, 484, 1118, 486, 1182, 486, 1114, 1192, 454, 458, 1120, 484, 1178, 1192, 454, 456, 1120, 484, 1122, 486, 1180, 484, 1122, 484, 1118, 488, 1122, 484, 1182, 484, 1124, 482, 1122, 486, 1120, 484, 1184, 482, 1118, 1190, 456, 452, 1126, 484, 1180, 1192, 454, 452, 1128, 482, 1122, 484, 1178, 1190, 454, 1160, 454, 1154, 466, 452, 1184, 1186, 454, 1156, 458, 1158, 456, 1156, 462, 1160}; // UNKNOWN 6C4EF873
int type; //hot/cold
*/
//#include "wifi_info.h"
#include "WiFiManager.h"
WiFiManager manager;

#define LOG_D(fmt, ...) printf_P(PSTR(fmt "\n") , ##VA_ARGS);

// access your HomeKit characteristics defined in my_accessory.c
extern "C" homekit_server_config_t config;
extern "C" homekit_characteristic_t led_bri;
extern "C" void occupancy_toggle();
extern "C" void led_toggle();
extern "C" void accessory_init();

#define PIN_SWITCH 2 //Relay pin
#define SwitchInit true // initial state
#define RelayTime 200 // ms till return to initial state, zero to ignore
long start=millis();

void blink_led(int interval, int count) {
for (int i = 0; i < count; i++) {
builtinledSetStatus(true);
delay(interval);
builtinledSetStatus(false);
delay(interval);
}
}
//void pp(int i){
// Serial.println(i);
//}

void setup() {
Serial.begin(115200);

// pinMode (irLed, OUTPUT);
manager.autoConnect("HOMEKIT");
// wifi_connect(); // in wifi_info.h
my_homekit_setup();
}

void loop() {
my_homekit_loop();
delay(10);
if (millis()-start>5000) {
start=millis();Serial.println(led_bri.value.int_value);
}
if (!digitalRead(0)) { //reset all settings
digitalWrite(2, LOW);
delay(2000);
if (!digitalRead(0)) {
homekit_storage_reset();
// manager.resetSettings();
ESP.reset();
}
digitalWrite(2, HIGH);
}

}

void builtinledSetStatus(bool on) {
digitalWrite(PIN_SWITCH, on ? LOW : HIGH);
}

//==============================
// HomeKit setup and loop
//==============================

ButtonDebounce btn(0, INPUT_PULLUP, LOW);
ButtonHandler btnHandler;

void IRAM_ATTR btnInterrupt() {
btn.update();
}

static uint32_t next_heap_millis = 0;

//Called when the switch value is changed by iOS Home APP
void led_on_setter(homekit_value_t value) {
/* bool on = value.bool_value;
led_on.value.bool_value = on; //sync the value
LOG_D("Switch: %s", on ? "ON" : "OFF");
// digitalWrite(PIN_SWITCH, on ? LOW : HIGH);
// if (RelayTime) {
// delay(RelayTime);
// digitalWrite(PIN_SWITCH, SwitchInit);
// }*/
//int led_br = value.int_value;
led_bri.value.int_value = value.int_value;

// int pwm = PWMRANGE - (int) (led_bri * 1.0 * PWMRANGE / 100.0 + 0.5f);
//Serial.println(pwm);
Serial.println(int(led_bri.value.int_value));
}

void my_homekit_setup() {
// digitalWrite(PIN_SWITCH, SwitchInit);
// pinMode(PIN_SWITCH, OUTPUT);

//Add the .setter function to get the switch-event sent from iOS Home APP.
//The .setter should be added before arduino_homekit_setup.
//HomeKit sever uses the .setter_ex internally, see homekit_accessories_init function.
//Maybe this is a legacy design issue in the original esp-homekit library,
//and I have no reason to modify this "feature".

// led_bri.setter = led_on_setter;
arduino_homekit_setup(&config);

//report the switch value to HomeKit if it is changed (e.g. by a physical button)
// bool switch_is_on = true/false;
// cha_switch_on.value.bool_value = switch_is_on;
// homekit_characteristic_notify(&cha_switch_on, cha_switch_on.value);
btn.setCallback(std::bind(&ButtonHandler::handleChange, &btnHandler,
std::placeholders::_1));
btn.setInterrupt(btnInterrupt);
btnHandler.setIsDownFunction(std::bind(&ButtonDebounce::checkIsDown, &btn));
btnHandler.setCallback([](button_event e) {
if (e == BUTTON_EVENT_SINGLECLICK) {
LOG_D("Button Event: SINGLECLICK");
led_toggle();
} else if (e == BUTTON_EVENT_DOUBLECLICK) {
LOG_D("Button Event: DOUBLECLICK");
occupancy_toggle();
} else if (e == BUTTON_EVENT_LONGCLICK) {
LOG_D("Button Event: LONGCLICK");
LOG_D("Rebooting...");
// homekit_storage_reset();
// ESP.restart(); // or system_restart();
}
});
}

void my_homekit_loop() {
arduino_homekit_loop();
const uint32_t t = millis();
if (t > next_heap_millis) {
// show heap info every 5 seconds
next_heap_millis = t + 5 * 1000;
LOG_D("Free heap: %d, HomeKit clients: %d",
ESP.getFreeHeap(), arduino_homekit_connected_clients_count());

}
}`

from arduino-homekit-esp8266.

Mixiaoxiao avatar Mixiaoxiao commented on May 23, 2024

Read the Example01~04 to understand the full logic.
This is not an issue about this project, but a question about how to code.

Your characteristic BRIGHTNESS has its .setter and .getter, and you sync the brightness-value to var led_bri in function led_bri_set and your value in characteristic BRIGHTNESS is not synced. Two ways:

  • The brightness-value is var led_bri, write extern "C" int led_bri; and you can access the var led_bri in your ino.
  • Define your characteristic BRIGHTNESS as a var named e.g. cha_brightness (like led_on, cha_name ), and sync its value in its .setter function by writing cha_brightness.value.int_value = value.int_value; (See Example02_Switch)

BTW, the .setter and .getter functions logic is as follows:

  • When HomeKit changed the cha value:
    if cha has .setter then call its .setter function;
    else just change(sync to) cha's value.
  • When HomeKit need read the cha value: (e.g. sync value when reconnected)
    if cha has .getter then return the .getter function value (does not read its value);
    else just return its value.

I do think the design (by author maximkulkin) of .setter and .getter is not easy for coding beginners to understand, but it is a really good design to "hook" the cha changing and reading event. Also, there is a .callback can do this thing but it will give the coding beginners a more complex thing to understand.

from arduino-homekit-esp8266.

wahidsa avatar wahidsa commented on May 23, 2024

thank you so much for your help in my code.
i tried the first one>>> WORKED GREAT
GREAT WORK YOU DID

I even upgraded my skills to include many accessories :)

from arduino-homekit-esp8266.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.