From 22dad6dd469007c501a9fb75d94042d61d6b1b60 Mon Sep 17 00:00:00 2001 From: Joel Santos Date: Tue, 3 Oct 2023 00:17:04 +0100 Subject: [PATCH] feat(service): Adds HomeAssistant service --- README.md | 67 ++++++++++---------- service/homeassistant/README.md | 25 ++++++++ service/homeassistant/homeassistant.go | 60 ++++++++++++++++++ service/homeassistant/homeassistant_test.go | 69 +++++++++++++++++++++ 4 files changed, 188 insertions(+), 33 deletions(-) create mode 100644 service/homeassistant/README.md create mode 100644 service/homeassistant/homeassistant.go create mode 100644 service/homeassistant/homeassistant_test.go diff --git a/README.md b/README.md index 1b66c4a4..47ce37e7 100644 --- a/README.md +++ b/README.md @@ -77,39 +77,40 @@ Yes, please! Contributions of all kinds are very welcome! Feel free to check our > Click [here](https://github.com/nikoksr/notify/issues/new?assignees=&labels=affects%2Fservices%2C+good+first+issue%2C+hacktoberfest%2C+help+wanted%2C+type%2Fenhancement%2C+up+for+grabs&template=service-request.md&title=feat%28service%29%3A+Add+%5BSERVICE+NAME%5D+service) to request a missing service. -| Service | Path | Credits | Status | -|-----------------------------------------------------------------------------------|------------------------------------------|-------------------------------------------------------------------------------------------------|:------------------:| -| [Amazon SES](https://aws.amazon.com/ses) | [service/amazonses](service/amazonses) | [aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2) | :heavy_check_mark: | -| [Amazon SNS](https://aws.amazon.com/sns) | [service/amazonsns](service/amazonsns) | [aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2) | :heavy_check_mark: | -| [Bark](https://apps.apple.com/us/app/bark-customed-notifications/id1403753865) | [service/bark](service/bark) | - | :heavy_check_mark: | -| [DingTalk](https://www.dingtalk.com) | [service/dinding](service/dingding) | [blinkbean/dingtalk](https://github.com/blinkbean/dingtalk) | :heavy_check_mark: | -| [Discord](https://discord.com) | [service/discord](service/discord) | [bwmarrin/discordgo](https://github.com/bwmarrin/discordgo) | :heavy_check_mark: | -| [Email](https://wikipedia.org/wiki/Email) | [service/mail](service/mail) | [jordan-wright/email](https://github.com/jordan-wright/email) | :heavy_check_mark: | -| [Firebase Cloud Messaging](https://firebase.google.com/docs/cloud-messaging) | [service/fcm](service/fcm) | [appleboy/go-fcm](https://github.com/appleboy/go-fcm) | :heavy_check_mark: | - | [Google Chat](https://workspace.google.com/intl/en/products/chat/) | [service/googlechat](service/googlechat) | [googleapis/google-api-go-client](https://google.golang.org/api/chat/v1) | :heavy_check_mark: | -| [HTTP](https://wikipedia.org/wiki/Hypertext_Transfer_Protocol) | [service/http](service/http) | - | :heavy_check_mark: | -| [Lark](https://www.larksuite.com/) | [service/lark](service/lark) | [go-lark/lark](https://github.com/go-lark/lark) | :heavy_check_mark: | -| [Line](https://line.me) | [service/line](service/line) | [line/line-bot-sdk-go](https://github.com/line/line-bot-sdk-go) | :heavy_check_mark: | -| [Line Notify](https://notify-bot.line.me) | [service/line](service/line) | [utahta/go-linenotify](https://github.com/utahta/go-linenotify) | :heavy_check_mark: | -| [Mailgun](https://www.mailgun.com) | [service/mailgun](service/mailgun) | [mailgun/mailgun-go](https://github.com/mailgun/mailgun-go) | :heavy_check_mark: | -| [Matrix](https://www.matrix.org) | [service/matrix](service/matrix) | [mautrix/go](https://github.com/mautrix/go) | :heavy_check_mark: | -| [Microsoft Teams](https://www.microsoft.com/microsoft-teams) | [service/msteams](service/msteams) | [atc0005/go-teams-notify](https://github.com/atc0005/go-teams-notify) | :heavy_check_mark: | -| [Plivo](https://www.plivo.com) | [service/plivo](service/plivo) | [plivo/plivo-go](https://github.com/plivo/plivo-go) | :heavy_check_mark: | -| [Pushover](https://pushover.net/) | [service/pushover](service/pushover) | [gregdel/pushover](https://github.com/gregdel/pushover) | :heavy_check_mark: | -| [Pushbullet](https://www.pushbullet.com) | [service/pushbullet](service/pushbullet) | [cschomburg/go-pushbullet](https://github.com/cschomburg/go-pushbullet) | :heavy_check_mark: | -| [Reddit](https://www.reddit.com) | [service/reddit](service/reddit) | [vartanbeno/go-reddit](https://github.com/vartanbeno/go-reddit) | :heavy_check_mark: | -| [RocketChat](https://rocket.chat) | [service/rocketchat](service/rocketchat) | [RocketChat/Rocket.Chat.Go.SDK](https://github.com/RocketChat/Rocket.Chat.Go.SDK) | :heavy_check_mark: | -| [SendGrid](https://sendgrid.com) | [service/sendgrid](service/sendgrid) | [sendgrid/sendgrid-go](https://github.com/sendgrid/sendgrid-go) | :heavy_check_mark: | -| [Slack](https://slack.com) | [service/slack](service/slack) | [slack-go/slack](https://github.com/slack-go/slack) | :heavy_check_mark: | -| [Syslog](https://wikipedia.org/wiki/Syslog) | [service/syslog](service/syslog) | [log/syslog](https://pkg.go.dev/log/syslog) | :heavy_check_mark: | -| [Telegram](https://telegram.org) | [service/telegram](service/telegram) | [go-telegram-bot-api/telegram-bot-api](https://github.com/go-telegram-bot-api/telegram-bot-api) | :heavy_check_mark: | -| [TextMagic](https://www.textmagic.com) | [service/textmagic](service/textmagic) | [textmagic/textmagic-rest-go-v2](https://github.com/textmagic/textmagic-rest-go-v2) | :heavy_check_mark: | -| [Twilio](https://www.twilio.com/) | [service/twilio](service/twilio) | [kevinburke/twilio-go](https://github.com/kevinburke/twilio-go) | :heavy_check_mark: | -| [Twitter](https://twitter.com) | [service/twitter](service/twitter) | [drswork/go-twitter](https://github.com/drswork/go-twitter) | :heavy_check_mark: | -| [Viber](https://www.viber.com) | [service/viber](service/viber) | [mileusna/viber](https://github.com/mileusna/viber) | :heavy_check_mark: | -| [WeChat](https://www.wechat.com) | [service/wechat](service/wechat) | [silenceper/wechat](https://github.com/silenceper/wechat) | :heavy_check_mark: | -| [Webpush Notification](https://developer.mozilla.org/en-US/docs/Web/API/Push_API) | [service/webpush](service/webpush) | [SherClockHolmes/webpush-go](https://github.com/SherClockHolmes/webpush-go/) | :heavy_check_mark: | -| [WhatsApp](https://www.whatsapp.com) | [service/whatsapp](service/whatsapp) | [Rhymen/go-whatsapp](https://github.com/Rhymen/go-whatsapp) | :x: | +| Service | Path | Credits | Status | +| --------------------------------------------------------------------------------- | ---------------------------------------------- | ----------------------------------------------------------------------------------------------- | :----------------: | +| [Amazon SES](https://aws.amazon.com/ses) | [service/amazonses](service/amazonses) | [aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2) | :heavy_check_mark: | +| [Amazon SNS](https://aws.amazon.com/sns) | [service/amazonsns](service/amazonsns) | [aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2) | :heavy_check_mark: | +| [Bark](https://apps.apple.com/us/app/bark-customed-notifications/id1403753865) | [service/bark](service/bark) | - | :heavy_check_mark: | +| [DingTalk](https://www.dingtalk.com) | [service/dinding](service/dingding) | [blinkbean/dingtalk](https://github.com/blinkbean/dingtalk) | :heavy_check_mark: | +| [Discord](https://discord.com) | [service/discord](service/discord) | [bwmarrin/discordgo](https://github.com/bwmarrin/discordgo) | :heavy_check_mark: | +| [Email](https://wikipedia.org/wiki/Email) | [service/mail](service/mail) | [jordan-wright/email](https://github.com/jordan-wright/email) | :heavy_check_mark: | +| [Firebase Cloud Messaging](https://firebase.google.com/docs/cloud-messaging) | [service/fcm](service/fcm) | [appleboy/go-fcm](https://github.com/appleboy/go-fcm) | :heavy_check_mark: | +| [Google Chat](https://workspace.google.com/intl/en/products/chat/) | [service/googlechat](service/googlechat) | [googleapis/google-api-go-client](https://google.golang.org/api/chat/v1) | :heavy_check_mark: | +| [HTTP](https://wikipedia.org/wiki/Hypertext_Transfer_Protocol) | [service/http](service/http) | - | :heavy_check_mark: | +| [HomeAssistant](https://www.home-assistant.io/) | [service/homeassistant](service/homeassistant) | [service/http](service/http) | :heavy_check_mark: | +| [Lark](https://www.larksuite.com/) | [service/lark](service/lark) | [go-lark/lark](https://github.com/go-lark/lark) | :heavy_check_mark: | +| [Line](https://line.me) | [service/line](service/line) | [line/line-bot-sdk-go](https://github.com/line/line-bot-sdk-go) | :heavy_check_mark: | +| [Line Notify](https://notify-bot.line.me) | [service/line](service/line) | [utahta/go-linenotify](https://github.com/utahta/go-linenotify) | :heavy_check_mark: | +| [Mailgun](https://www.mailgun.com) | [service/mailgun](service/mailgun) | [mailgun/mailgun-go](https://github.com/mailgun/mailgun-go) | :heavy_check_mark: | +| [Matrix](https://www.matrix.org) | [service/matrix](service/matrix) | [mautrix/go](https://github.com/mautrix/go) | :heavy_check_mark: | +| [Microsoft Teams](https://www.microsoft.com/microsoft-teams) | [service/msteams](service/msteams) | [atc0005/go-teams-notify](https://github.com/atc0005/go-teams-notify) | :heavy_check_mark: | +| [Plivo](https://www.plivo.com) | [service/plivo](service/plivo) | [plivo/plivo-go](https://github.com/plivo/plivo-go) | :heavy_check_mark: | +| [Pushover](https://pushover.net/) | [service/pushover](service/pushover) | [gregdel/pushover](https://github.com/gregdel/pushover) | :heavy_check_mark: | +| [Pushbullet](https://www.pushbullet.com) | [service/pushbullet](service/pushbullet) | [cschomburg/go-pushbullet](https://github.com/cschomburg/go-pushbullet) | :heavy_check_mark: | +| [Reddit](https://www.reddit.com) | [service/reddit](service/reddit) | [vartanbeno/go-reddit](https://github.com/vartanbeno/go-reddit) | :heavy_check_mark: | +| [RocketChat](https://rocket.chat) | [service/rocketchat](service/rocketchat) | [RocketChat/Rocket.Chat.Go.SDK](https://github.com/RocketChat/Rocket.Chat.Go.SDK) | :heavy_check_mark: | +| [SendGrid](https://sendgrid.com) | [service/sendgrid](service/sendgrid) | [sendgrid/sendgrid-go](https://github.com/sendgrid/sendgrid-go) | :heavy_check_mark: | +| [Slack](https://slack.com) | [service/slack](service/slack) | [slack-go/slack](https://github.com/slack-go/slack) | :heavy_check_mark: | +| [Syslog](https://wikipedia.org/wiki/Syslog) | [service/syslog](service/syslog) | [log/syslog](https://pkg.go.dev/log/syslog) | :heavy_check_mark: | +| [Telegram](https://telegram.org) | [service/telegram](service/telegram) | [go-telegram-bot-api/telegram-bot-api](https://github.com/go-telegram-bot-api/telegram-bot-api) | :heavy_check_mark: | +| [TextMagic](https://www.textmagic.com) | [service/textmagic](service/textmagic) | [textmagic/textmagic-rest-go-v2](https://github.com/textmagic/textmagic-rest-go-v2) | :heavy_check_mark: | +| [Twilio](https://www.twilio.com/) | [service/twilio](service/twilio) | [kevinburke/twilio-go](https://github.com/kevinburke/twilio-go) | :heavy_check_mark: | +| [Twitter](https://twitter.com) | [service/twitter](service/twitter) | [drswork/go-twitter](https://github.com/drswork/go-twitter) | :heavy_check_mark: | +| [Viber](https://www.viber.com) | [service/viber](service/viber) | [mileusna/viber](https://github.com/mileusna/viber) | :heavy_check_mark: | +| [WeChat](https://www.wechat.com) | [service/wechat](service/wechat) | [silenceper/wechat](https://github.com/silenceper/wechat) | :heavy_check_mark: | +| [Webpush Notification](https://developer.mozilla.org/en-US/docs/Web/API/Push_API) | [service/webpush](service/webpush) | [SherClockHolmes/webpush-go](https://github.com/SherClockHolmes/webpush-go/) | :heavy_check_mark: | +| [WhatsApp](https://www.whatsapp.com) | [service/whatsapp](service/whatsapp) | [Rhymen/go-whatsapp](https://github.com/Rhymen/go-whatsapp) | :x: | ## Special Thanks diff --git a/service/homeassistant/README.md b/service/homeassistant/README.md new file mode 100644 index 00000000..41a5b813 --- /dev/null +++ b/service/homeassistant/README.md @@ -0,0 +1,25 @@ +# HomeAssistant service + +[HomeAssistant](https://www.home-assistant.io) is an application that handles home automation and integration + +## Usage + +[HomeAssistant webhook trigger](https://www.home-assistant.io/docs/automation/trigger/#webhook-trigger) + +```go +// Create a HomeAssistant service +haService := homeassistant.New() + +// Add webhook +haService.AddWebhook("https://url-to-home-assistant", "", "") + +// Tell our notifier to use the service. +notify.UseServices(haService) + +// Send a test message. +_ = notify.Send( + context.Background(), + "Subject/Title", + "The actual message - Hello, you awesome gophers! :)", +) +``` diff --git a/service/homeassistant/homeassistant.go b/service/homeassistant/homeassistant.go new file mode 100644 index 00000000..4d0e110b --- /dev/null +++ b/service/homeassistant/homeassistant.go @@ -0,0 +1,60 @@ +package homeassistant + +import ( + "context" + stdhttp "net/http" + "strings" + + "github.com/nikoksr/notify/service/http" +) + +// HomeAssistant struct holds necessary data to communicate with the HomeAssistant API. +type HomeAssistant struct { + httpClient http.Service +} + +// New returns a new instance of a HomeAssistant notification service. +func New() (*HomeAssistant, error) { + h := HomeAssistant{ + httpClient: *http.New(), + } + return &h, nil +} + +// AddWebhook takes HomeAssistant automation webhooks and adds them. The Send method will send to all these +// baseUrl should be the home assistant base url for example https://your-home-assistant:8123 +// hookId should be what was set at the trigger of the webhook +// method should be the method selected at the trigger of the webhook +// For more information read HomeAssistant documentation at: +// - https://www.home-assistant.io/docs/automation/trigger/#webhook-trigger +func (h *HomeAssistant) AddWebhook(baseUrl string, hookId string, method string) { + baseUrl = strings.TrimRight(baseUrl, "/") + u := baseUrl + "/api/webhook/" + hookId + + // From example: + // curl -X POST -d 'key=value&key2=value2' https://your-home-assistant:8123/api/webhook/some_hook_id + + hook := &http.Webhook{ + URL: u, + Header: stdhttp.Header{}, + ContentType: "application/json", + Method: strings.ToUpper(method), + BuildPayload: func(subject, message string) (payload any) { + dataMap := make(map[string]string) + dataMap["subject"] = subject + dataMap["message"] = message + + return dataMap + }, + } + + h.httpClient.AddReceivers(hook) +} + +// Send takes a subject and a message and sends them to all previously set webhooks +func (h HomeAssistant) Send(ctx context.Context, subject, message string) error { + // TODO: should setup mqtt automation integration as well + // https://www.home-assistant.io/docs/automation/trigger/#mqtt-trigger + + return h.httpClient.Send(ctx, subject, message) +} diff --git a/service/homeassistant/homeassistant_test.go b/service/homeassistant/homeassistant_test.go new file mode 100644 index 00000000..4de6be96 --- /dev/null +++ b/service/homeassistant/homeassistant_test.go @@ -0,0 +1,69 @@ +package homeassistant + +import ( + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNew(t *testing.T) { + t.Parallel() + + s1, err := New() + assert.NotNil(t, s1, "service should not be nil") + assert.Nil(t, err, "error should not exist") + + s2, err := New() + assert.NotNil(t, s2, "service should not be nil") + assert.Equal(t, s1, s2, "services should be equal") + assert.Nil(t, err, "error should not exist") +} + +func TestService_Send(t *testing.T) { + t.Parallel() + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + hookId := "very_long_hook_id_to_test_out" + subject := "test subject" + message := "test message" + + sent := false + svr := httptest.NewServer(http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) { + if !strings.Contains(r.URL.Path, "/api/webhook/"+hookId) { + return + } + + var m map[string]string + err := json.NewDecoder(r.Body).Decode(&m) + if err != nil || m == nil { + return + } + + if s, ok := m["subject"]; !ok || s != subject { + return + } + + if s, ok := m["message"]; !ok || s != message { + return + } + + sent = true + })) + defer svr.Close() + + // Create service with local server as receiver + service, _ := New() + service.AddWebhook(svr.URL, hookId, "POST") + + // Sending this notification should work without any issues + err := service.Send(ctx, subject, message) + assert.NoError(t, err, "error should be nil") + assert.True(t, sent, "message was not received") +}