Beispiel #1
0
func TestGetAccessories(t *testing.T) {
	info := model.Info{
		Name:         "My Accessory",
		SerialNumber: "001",
		Manufacturer: "Google",
		Model:        "Accessory",
	}

	a := accessory.New(info)

	m := container.NewContainer()
	m.AddAccessory(a)

	controller := NewContainerController(m)

	var b bytes.Buffer
	r, err := controller.HandleGetAccessories(&b)

	if err != nil {
		t.Fatal(err)
	}
	if r == nil {
		t.Fatal("no response")
	}

	bytes, _ := ioutil.ReadAll(r)
	var returnedContainer container.Container
	if err := json.Unmarshal(bytes, &returnedContainer); err != nil {
		t.Fatal(err)
	}

	if returnedContainer.Equal(m) == false {
		t.Fatal("containers not the same")
	}
}
func TestPutCharacteristic(t *testing.T) {
	info := model.Info{
		Name:         "My Switch",
		SerialNumber: "001",
		Manufacturer: "Google",
		Model:        "Bridge",
	}

	a := accessory.NewSwitch(info)
	a.SetOn(false)

	m := container.NewContainer()
	m.AddAccessory(a.Accessory)

	// find on characteristic with type CharTypePowerState
	var cid int64
	for _, s := range a.Accessory.Services {
		for _, c := range s.Characteristics {
			if c.Type == characteristic.CharTypePowerState {
				cid = c.ID
			}
		}
	}

	if cid == 0 {
		t.Fatal("characteristic not found")
	}

	char := data.Characteristic{AccessoryID: 1, ID: cid, Value: true}
	var slice []data.Characteristic
	slice = append(slice, char)

	chars := data.Characteristics{Characteristics: slice}
	b, err := json.Marshal(chars)

	if err != nil {
		t.Fatal(err)
	}

	var buffer bytes.Buffer
	buffer.Write(b)

	controller := NewCharacteristicController(m)
	err = controller.HandleUpdateCharacteristics(&buffer, characteristic.TestConn)

	if err != nil {
		t.Fatal(err)
	}

	if is, want := a.IsOn(), true; is != want {
		t.Fatalf("is=%v want=%v", is, want)
	}
}
Beispiel #3
0
func TestCharacteristicNotification(t *testing.T) {
	a := accessory.New(info)
	c := container.NewContainer()
	c.AddAccessory(a)

	buffer, err := Body(a, a.Info.Name.Characteristic)
	if err != nil {
		t.Fatal(err)
	}

	bytes, err := ioutil.ReadAll(buffer)

	if err != nil {
		t.Fatal(err)
	}
	if is, want := string(bytes), `{"characteristics":[{"aid":1,"iid":2,"value":"My Bridge"}]}`; is != want {
		t.Fatalf("is=%v want=%v", is, want)
	}
}
func TestGetCharacteristic(t *testing.T) {
	info := model.Info{
		Name:         "My Bridge",
		SerialNumber: "001",
		Manufacturer: "Google",
		Model:        "Bridge",
	}

	a := accessory.New(info)

	m := container.NewContainer()
	m.AddAccessory(a)

	aid := a.GetID()
	cid := a.Info.Name.GetID()
	values := idsString(aid, cid)
	controller := NewCharacteristicController(m)
	res, err := controller.HandleGetCharacteristics(values)

	if err != nil {
		t.Fatal(err)
	}

	b, err := ioutil.ReadAll(res)

	if err != nil {
		t.Fatal(err)
	}

	var chars data.Characteristics
	err = json.Unmarshal(b, &chars)

	if err != nil {
		t.Fatal(err)
	}

	if is, want := len(chars.Characteristics), 1; is != want {
		t.Fatalf("is=%v want=%v", is, want)
	}
	if x := chars.Characteristics[0].Value; x != "My Bridge" {
		t.Fatal(x)
	}
}
Beispiel #5
0
// NewIPTransport creates a transport to provide accessories over IP.
// The pairing is secured using a 8-numbers pin.
// If more than one accessory is provided, the first becomes a bridge in HomeKit.
// It's fine when the bridge has no explicit services.
//
// All accessory specific data (crypto keys, ids) is stored in a folder named after the first accessory.
// So changing the order of the accessories or renaming the first accessory makes the stored
// data inaccessible to the tranport. In this case new crypto keys are created and the accessory
// appears as a new one to clients.
func NewIPTransport(pin string, pth string, a *accessory.Accessory, as ...*accessory.Accessory) (Transport, error) {
	// Find transport name which is visible in mDNS
	name := a.Name()
	if len(name) == 0 {
		log.Fatal("Invalid empty name for first accessory")
	}

	hapPin, err := NewPin(pin)
	if err != nil {
		return nil, err
	}

	storage, err := util.NewFileStorage(path.Join(pth, name))
	if err != nil {
		return nil, err
	}

	// Find transport uuid which appears as "id" txt record in mDNS and
	// must be unique and stay the same over time
	uuid := transportUUIDInStorage(storage)
	database := db.NewDatabaseWithStorage(storage)
	device, err := netio.NewSecuredDevice(uuid, hapPin, database)

	t := &ipTransport{
		database:  database,
		name:      name,
		device:    device,
		container: container.NewContainer(),
		mutex:     &sync.Mutex{},
		context:   netio.NewContextForSecuredDevice(device),
		emitter:   event.NewEmitter(),
	}

	t.addAccessory(a)
	for _, a := range as {
		t.addAccessory(a)
	}

	t.emitter.AddListener(t)

	return t, err
}
Beispiel #6
0
// NewIPTransport creates a transport to provide accessories over IP.
//
// The IP transports stores the crypto keys inside a database, which
// is by default inside a folder at the current working directory.
// The folder is named exactly as the accessory name.
//
// The transports can contain more than one accessory. If this is the
// case, the first accessory acts as the HomeKit bridge.
//
// *Important:* Changing the name of the accessory, or letting multiple
// transports store the data inside the same database lead to
// unexpected behavior – don't do that.
//
// The transport is secured with an 8-digit pin, which must be entered
// by an iOS client to successfully pair with the accessory. If the
// provided transport config does not specify any pin, 00102003 is used.
func NewIPTransport(config Config, a *accessory.Accessory, as ...*accessory.Accessory) (Transport, error) {
	// Find transport name which is visible in mDNS
	name := a.Name()
	if len(name) == 0 {
		log.Fatal("Invalid empty name for first accessory")
	}

	default_config := Config{
		StoragePath: name,
		Pin:         "00102003",
		Port:        "",
	}

	if dir := config.StoragePath; len(dir) > 0 {
		default_config.StoragePath = dir
	}

	if pin := config.Pin; len(pin) > 0 {
		default_config.Pin = pin
	}

	if port := config.Port; len(port) > 0 {
		default_config.Port = ":" + port
	}

	storage, err := util.NewFileStorage(default_config.StoragePath)
	if err != nil {
		return nil, err
	}

	// Find transport uuid which appears as "id" txt record in mDNS and
	// must be unique and stay the same over time
	uuid := transportUUIDInStorage(storage)
	database := db.NewDatabaseWithStorage(storage)

	hap_pin, err := NewPin(default_config.Pin)
	if err != nil {
		return nil, err
	}

	device, err := netio.NewSecuredDevice(uuid, hap_pin, database)

	t := &ipTransport{
		database:  database,
		name:      name,
		device:    device,
		config:    default_config,
		container: container.NewContainer(),
		mutex:     &sync.Mutex{},
		context:   netio.NewContextForSecuredDevice(device),
		emitter:   event.NewEmitter(),
	}

	t.addAccessory(a)
	for _, a := range as {
		t.addAccessory(a)
	}

	t.emitter.AddListener(t)

	return t, err
}