hapitypes

package
v0.0.0-...-f8c32d9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 13, 2021 License: Apache-2.0 Imports: 7 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	DeviceClassGeneric        = &DeviceClass{"Generic", homeassistant.IconEye, "OTHER"}
	DeviceClassLight          = &DeviceClass{"Light", homeassistant.IconLightbulb, "LIGHT"}
	DeviceClassRollerBlind    = &DeviceClass{"Roller blind", homeassistant.IconBlinds, "INTERIOR_BLIND"}
	DeviceClassRemote         = &DeviceClass{"Remote", homeassistant.IconRemote, "OTHER"}
	DeviceClassAmplifier      = &DeviceClass{"Amplifier", homeassistant.IconSpeaker, "SPEAKER"}
	DeviceClassTV             = &DeviceClass{"TV", homeassistant.IconTelevision, "TV"}
	DeviceClassClimateSensor  = &DeviceClass{"Climate sensor", homeassistant.IconThermometer, "TEMPERATURE_SENSOR"}
	DeviceClassPresenceSensor = &DeviceClass{"Presence sensor", homeassistant.IconHome, "MOTION_SENSOR"}
	DeviceClassSensor         = &DeviceClass{"Sensor", homeassistant.IconGauge, "OTHER"}
	DeviceClassFan            = &DeviceClass{"Fan", homeassistant.IconFan, "FAN"}
	DeviceClassDoor           = &DeviceClass{"Door", homeassistant.IconDoorClosed, "DOOR"}
	DeviceClassComputer       = &DeviceClass{"Computer", homeassistant.IconTablet, "COMPUTER"}
	DeviceClassDisplay        = &DeviceClass{"Display", homeassistant.IconMonitor, "SCREEN"}
	DeviceClassSmartPlug      = &DeviceClass{"Smart plug", homeassistant.IconPower, "SMARTPLUG"} // used only if user doesn't specify a specific device connected to the smart plug
	DeviceClassSleepingSensor = &DeviceClass{"Sleeping sensor", homeassistant.IconSleep, "WEARABLE"}
)
View Source
var DeviceClassById = map[string]*DeviceClass{
	"Generic":        DeviceClassGeneric,
	"Light":          DeviceClassLight,
	"RollerBlind":    DeviceClassRollerBlind,
	"Remote":         DeviceClassRemote,
	"Amplifier":      DeviceClassAmplifier,
	"TV":             DeviceClassTV,
	"ClimateSensor":  DeviceClassClimateSensor,
	"PresenceSensor": DeviceClassPresenceSensor,
	"Sensor":         DeviceClassSensor,
	"Fan":            DeviceClassFan,
	"Door":           DeviceClassDoor,
	"Computer":       DeviceClassComputer,
	"Display":        DeviceClassDisplay,
	"SmartPlug":      DeviceClassSmartPlug,
	"SleepingSensor": DeviceClassSleepingSensor,
}
View Source
var ErrDeviceNotFound = errors.New("device not found")

Functions

This section is empty.

Types

type ActionConfig

type ActionConfig struct {
	Device          string `json:"device"`
	Verb            string `json:"verb"`             // powerOn/powerOff/powerToggle/blink/ir/setBooleanFalse/setBooleanTrue/sleep/playback/notify/speak
	IrCommand       string `json:"ir_command"`       // used by: ir
	Boolean         string `json:"boolean"`          // used by: setBooleanTrue/setBooleanFalse
	DurationSeconds int    `json:"duration_seconds"` // used by: sleep
	PlaybackAction  string `json:"playback_action"`  // used by: playback
	NotifyMessage   string `json:"notify_message"`   // used by: notify
	SpeakPhrase     string `json:"speak_phrase"`     // used by: speak
}

type Adapter

type Adapter struct {
	Conf AdapterConfig

	Outbound chan OutboundEvent // outbound events going to lights, TV, amplifier etc.
	Logl     *logex.Leveled
	Log      *log.Logger // if one wants to pass native logger to libraries etc.
	// contains filtered or unexported fields
}

func NewAdapter

func NewAdapter(conf AdapterConfig, confFile *ConfigFile, inbound *InboundFabric, logger *log.Logger) *Adapter

func (*Adapter) GetConfigFileDeprecated

func (a *Adapter) GetConfigFileDeprecated() *ConfigFile

FIXME: remove the need for this some adapters need this when they need to reflect on their own / all devices

func (*Adapter) LogUnsupportedEvent

func (a *Adapter) LogUnsupportedEvent(e OutboundEvent)

func (*Adapter) Receive

func (a *Adapter) Receive(e InboundEvent)

func (*Adapter) Send

func (a *Adapter) Send(e OutboundEvent)

type AdapterConfig

type AdapterConfig struct {
	Id   string `json:"id"`
	Type string `json:"type"`

	// generic attributes usable by many adapters
	Url string `json:"url"` // (or base URL), used by: alexa | screenserver | homeassistant | tradfi | zigbee2mqtt | harmonyhub

	ParticleId          string `json:"particle_id,omitempty"`
	ParticleAccessToken string `json:"particle_access_token,omitempty"`

	SqsKeyId                string `json:"sqs_key_id,omitempty"`
	SqsKeySecret            string `json:"sqs_key_secret,omitempty"`
	SqsAlexaUsertokenHash   string `json:"sqs_alexa_usertoken_hash,omitempty"`
	AlexaOauth2ClientId     string `json:"alexa_oauth2_client_id"`
	AlexaOauth2ClientSecret string `json:"alexa_oauth2_client_secret"`
	AlexaOauth2UserToken    string `json:"alexa_oauth2_user_token"`

	IrSimulatorKey string `json:"irsimulator_button,omitempty"`

	MqttTopicPrefix string `json:"mqtt_topic_prefix,omitempty"`

	TradfriUser string `json:"tradfri_user"`
	TradfriPsk  string `json:"tradfri_psk"`

	PresenceByPingDevice []PresenceByPingDevice `json:"presencebypingdevice"`

	UrlChangeDetectors []UrlChangeDetector `json:"url_change_detector"`

	DevicegroupDevices []string `json:"devicegroup_devs"`
}

type BatteryStatusEvent

type BatteryStatusEvent struct {
	Device     string
	BatteryPct uint // 0-100 %
	Voltage    uint // [mV]
}

func NewBatteryStatusEvent

func NewBatteryStatusEvent(deviceId string, batteryPct uint, voltage uint) *BatteryStatusEvent

func (*BatteryStatusEvent) InboundEventType

func (e *BatteryStatusEvent) InboundEventType() string

type BlinkEvent

type BlinkEvent struct {
	DeviceId string
}

func NewBlinkEvent

func NewBlinkEvent(deviceId string) *BlinkEvent

func (*BlinkEvent) InboundEventType

func (e *BlinkEvent) InboundEventType() string

func (*BlinkEvent) OutboundEventType

func (e *BlinkEvent) OutboundEventType() string

func (*BlinkEvent) RedirectInbound

func (e *BlinkEvent) RedirectInbound(toDeviceId string) InboundEvent

type BrightnessEvent

type BrightnessEvent struct {
	DeviceIdOrDeviceGroupId string
	Brightness              uint // 0..100 %
}

func NewBrightnessEvent

func NewBrightnessEvent(deviceIdOrDeviceGroupId string, brightness uint) *BrightnessEvent

func (*BrightnessEvent) InboundEventType

func (e *BrightnessEvent) InboundEventType() string

type BrightnessMsg

type BrightnessMsg struct {
	DeviceId   string
	Brightness uint
	LastColor  RGB
}

func NewBrightnessMsg

func NewBrightnessMsg(deviceId string, brightness uint, lastColor RGB) *BrightnessMsg

func (*BrightnessMsg) OutboundEventType

func (e *BrightnessMsg) OutboundEventType() string

func (*BrightnessMsg) RedirectInbound

func (e *BrightnessMsg) RedirectInbound(toDeviceId string) InboundEvent

type Capabilities

type Capabilities struct {
	Power                     bool `json:"power"`
	Brightness                bool `json:"brightness"`
	Color                     bool `json:"color"`
	ColorTemperature          bool `json:"colortemperature"`
	ColorSeparateWhiteChannel bool `json:"color_separate_white_channel"`
	Playback                  bool `json:"playback"`
	ReportsTemperature        bool `json:"reports_temperature"`
	VirtualSwitch             bool `json:"virtual_switch"` // can send fake contact sensor triggers to Alexa to trigger routines
	CoverPosition             bool `json:"cover_position"`
}

type ColorMsg

type ColorMsg struct {
	DeviceId string
	Color    RGB
}

func NewColorMsg

func NewColorMsg(deviceId string, color RGB) *ColorMsg

func (*ColorMsg) InboundEventType

func (e *ColorMsg) InboundEventType() string

func (*ColorMsg) OutboundEventType

func (e *ColorMsg) OutboundEventType() string

func (*ColorMsg) RedirectInbound

func (e *ColorMsg) RedirectInbound(toDeviceId string) InboundEvent

type ColorTemperatureEvent

type ColorTemperatureEvent struct {
	Device              string
	TemperatureInKelvin uint
}

func NewColorTemperatureEvent

func NewColorTemperatureEvent(device string, temperatureInKelvin uint) *ColorTemperatureEvent

func (*ColorTemperatureEvent) InboundEventType

func (e *ColorTemperatureEvent) InboundEventType() string

func (*ColorTemperatureEvent) OutboundEventType

func (e *ColorTemperatureEvent) OutboundEventType() string

func (*ColorTemperatureEvent) RedirectInbound

func (e *ColorTemperatureEvent) RedirectInbound(toDeviceId string) InboundEvent

type ConditionConfig

type ConditionConfig struct {
	Type            string `json:"type"` // boolean-is-true/boolean-is-false/boolean-not-changed-within
	Boolean         string `json:"boolean"`
	DurationSeconds int    `json:"duration_seconds"`
}

type ConfigFile

type ConfigFile struct {
	Adapters      []AdapterConfig     `json:"adapter"`
	Devices       []DeviceConfig      `json:"device"`
	DeviceGroups  []DeviceGroupConfig `json:"devicegroup"`
	Persons       []Person            `json:"person"`
	Subscriptions []SubscribeConfig   `json:"subscribe"`
}

func (*ConfigFile) FindDeviceConfigByAdaptersDeviceId

func (c *ConfigFile) FindDeviceConfigByAdaptersDeviceId(adaptersDeviceId string) *DeviceConfig

type ContactEvent

type ContactEvent struct {
	Device  string
	Contact bool
	When    time.Time
}

func NewContactEvent

func NewContactEvent(deviceId string, contact bool, now time.Time) *ContactEvent

func (*ContactEvent) InboundEventType

func (e *ContactEvent) InboundEventType() string

type CoverPositionEvent

type CoverPositionEvent struct {
	DeviceId string
	Position uint // 0-100 %
}

func NewCoverPositionEvent

func NewCoverPositionEvent(deviceId string, position uint) *CoverPositionEvent

func (*CoverPositionEvent) InboundEventType

func (e *CoverPositionEvent) InboundEventType() string

func (*CoverPositionEvent) OutboundEventType

func (e *CoverPositionEvent) OutboundEventType() string

func (*CoverPositionEvent) RedirectInbound

func (e *CoverPositionEvent) RedirectInbound(toDeviceId string) InboundEvent

type Device

type Device struct {
	Conf DeviceConfig

	DeviceType DeviceType

	// probably turned on if true
	// might be turned on even if false,
	ProbablyTurnedOn bool

	LastColor RGB

	LastTemperatureHumidityPressureEvent *TemperatureHumidityPressureEvent

	// metrics
	LinkQualityMetric *constmetrics.Ref
	TemperatureMetric *constmetrics.Ref
	HumidityMetric    *constmetrics.Ref
	PressureMetric    *constmetrics.Ref
	BatteryPctMetric  *constmetrics.Ref

	LastOnline             *time.Time
	LastMotion             *time.Time
	LastExplicitPowerEvent *time.Time
	LastContact            *ContactEvent

	LinkQuality    uint // 0-100 %
	BatteryPct     uint // 0-100 %
	BatteryVoltage uint // [mV]
}

func NewDevice

func NewDevice(conf DeviceConfig, snapshot DeviceStateSnapshot) (*Device, error)

func (*Device) RestoreStateFromSnapshot

func (d *Device) RestoreStateFromSnapshot(snapshot DeviceStateSnapshot) error

func (*Device) SnapshotState

func (d *Device) SnapshotState() (*DeviceStateSnapshot, error)

type DeviceClass

type DeviceClass struct {
	FriendlyName      string // user-friendly name
	HomeAssistantIcon homeassistant.IconId
	AlexaCategory     string // available values https://developer.amazon.com/docs/device-apis/alexa-discovery.html#display-categories
}

device's main type category. e.g. light, without going deeper into its characteristics (RGB light, color temperature controllable). you can think of this as device type icon ("light bulb").

type DeviceConfig

type DeviceConfig struct {
	DeviceId         string `json:"id"`
	Type             string `json:"type"`
	AdapterId        string `json:"adapter"`
	AdaptersDeviceId string `json:"adapters_device_id,omitempty"`
	Name             string `json:"name"`
	Description      string `json:"description"`
	PowerOnCmd       string `json:"power_on_cmd,omitempty"`
	PowerOffCmd      string `json:"power_off_cmd,omitempty"`

	// there are rare times when you have to hint which type of device you have. for example we cannot
	// infer which type a smart plug controls if all we know is "we communicate with Sonoff Basic"
	DeviceClassId string `json:"device_class,omitempty"`

	VoiceAssistant bool `json:"voice_assistant,omitempty"`

	EventghostAddr   string `json:"eventghost_addr,omitempty"` // if specified, we connect to the PC direction for sending events
	EventghostSecret string `json:"eventghost_secret,omitempty"`
}

func (*DeviceConfig) Class

func (d *DeviceConfig) Class() (*DeviceClass, error)

gets device's explicitly set device class or if not found, device class from device type

type DeviceGroup

type DeviceGroup struct {
	Id        string
	Name      string
	DeviceIds []string
}

func NewDeviceGroup

func NewDeviceGroup(id string, name string, deviceIds []string) *DeviceGroup

type DeviceGroupConfig

type DeviceGroupConfig struct {
	DeviceId string   `json:"device_id"`
	Name     string   `json:"name"`
	Devices  []string `json:"devices"`
}

these are transparently generated to adapter + device combo

type DeviceStateSnapshot

type DeviceStateSnapshot struct {
	ProbablyTurnedOn                     bool                              `json:"probably_turned_on"`
	LastColor                            RGB                               `json:"last_color"`
	LastTemperatureHumidityPressureEvent *TemperatureHumidityPressureEvent `json:"last_temperaturehumiditypressure"`
	LastOnline                           *time.Time                        `json:"last_online"`
	LinkQuality                          uint                              `json:"link_quality_pct"`
	BatteryPct                           uint                              `json:"battery_pct"`
	BatteryVoltage                       uint                              `json:"battery_voltage_mv"`
}

TODO: just compose device's state with this? TODO: LastTemperatureHumidityPressureEvent should have explicit JSON annotations

type DeviceType

type DeviceType struct {
	Name         string
	Manufacturer string
	Model        string
	BatteryType  string
	LinkToManual string
	Class        *DeviceClass // broad categorization of the device - its "icon"
	Capabilities Capabilities
}

func ResolveDeviceType

func ResolveDeviceType(t string) (*DeviceType, error)

type InboundEvent

type InboundEvent interface {
	InboundEventType() string
}

command we are receiving from another system or sensor

type InboundFabric

type InboundFabric struct {
	Ch chan InboundEvent
	// contains filtered or unexported fields
}

func NewInboundFabric

func NewInboundFabric(logl *logex.Leveled) *InboundFabric

func (*InboundFabric) Receive

func (f *InboundFabric) Receive(e InboundEvent)

type InfraredEvent

type InfraredEvent struct {
	Device  string
	Command string
}

func NewInfraredEvent

func NewInfraredEvent(device string, command string) *InfraredEvent

func (*InfraredEvent) InboundEventType

func (e *InfraredEvent) InboundEventType() string

func (*InfraredEvent) OutboundEventType

func (e *InfraredEvent) OutboundEventType() string

func (*InfraredEvent) RedirectInbound

func (e *InfraredEvent) RedirectInbound(toDeviceId string) InboundEvent

type LinkQualityEvent

type LinkQualityEvent struct {
	Device      string
	LinkQuality uint // 0-100 %
}

func NewLinkQualityEvent

func NewLinkQualityEvent(deviceId string, linkQuality uint) *LinkQualityEvent

func (*LinkQualityEvent) InboundEventType

func (e *LinkQualityEvent) InboundEventType() string

type MotionEvent

type MotionEvent struct {
	Device      string
	Movement    bool
	Illuminance uint
}

func NewMotionEvent

func NewMotionEvent(deviceId string, movement bool, illuminance uint) *MotionEvent

func (*MotionEvent) InboundEventType

func (e *MotionEvent) InboundEventType() string

type NotificationEvent

type NotificationEvent struct {
	Device  string
	Message string
}

func NewNotificationEvent

func NewNotificationEvent(device string, message string) *NotificationEvent

func (*NotificationEvent) InboundEventType

func (e *NotificationEvent) InboundEventType() string

func (*NotificationEvent) OutboundEventType

func (e *NotificationEvent) OutboundEventType() string

func (*NotificationEvent) RedirectInbound

func (e *NotificationEvent) RedirectInbound(toDeviceId string) InboundEvent

type OutboundEvent

type OutboundEvent interface {
	OutboundEventType() string
	RedirectInbound(toDeviceId string) InboundEvent
}

event that we are sending to a device

type Person

type Person struct {
	Id string `json:"id"`
}

type PersonPresenceChangeEvent

type PersonPresenceChangeEvent struct {
	PersonId string
	Present  bool
}

func NewPersonPresenceChangeEvent

func NewPersonPresenceChangeEvent(personId string, present bool) *PersonPresenceChangeEvent

func (*PersonPresenceChangeEvent) InboundEventType

func (e *PersonPresenceChangeEvent) InboundEventType() string

type PlaySoundEvent

type PlaySoundEvent struct {
	Device string
	Url    string // sound file to play (at least support mp3). must be accessible via raw HTTP GET
}

func NewPlaySoundEvent

func NewPlaySoundEvent(deviceId string, message string) *PlaySoundEvent

func (*PlaySoundEvent) InboundEventType

func (e *PlaySoundEvent) InboundEventType() string

func (*PlaySoundEvent) OutboundEventType

func (e *PlaySoundEvent) OutboundEventType() string

func (*PlaySoundEvent) RedirectInbound

func (e *PlaySoundEvent) RedirectInbound(toDeviceId string) InboundEvent

type PlaybackEvent

type PlaybackEvent struct {
	Device string
	Action string
}

func NewPlaybackEvent

func NewPlaybackEvent(device string, action string) *PlaybackEvent

func (*PlaybackEvent) InboundEventType

func (e *PlaybackEvent) InboundEventType() string

func (*PlaybackEvent) OutboundEventType

func (e *PlaybackEvent) OutboundEventType() string

func (*PlaybackEvent) RedirectInbound

func (e *PlaybackEvent) RedirectInbound(toDeviceId string) InboundEvent

type PowerDiff

type PowerDiff struct {
	Device string
	On     bool
}

type PowerEvent

type PowerEvent struct {
	DeviceIdOrDeviceGroupId string
	Kind                    PowerKind
	// whether this was explicitly asked by the user, or generated (f.ex. by a device
	// group on => multiple ons for different devices)
	Explicit bool
}

func NewPowerEvent

func NewPowerEvent(deviceIdOrDeviceGroupId string, kind PowerKind, explicit bool) *PowerEvent

func NewPowerToggleEvent

func NewPowerToggleEvent(deviceIdOrDeviceGroupId string, explicit bool) PowerEvent

func (*PowerEvent) InboundEventType

func (e *PowerEvent) InboundEventType() string

type PowerKind

type PowerKind int
const (
	PowerKindOn PowerKind = iota
	PowerKindOff
	PowerKindToggle
)

type PowerManager

type PowerManager struct {
	// contains filtered or unexported fields
}

func NewPowerManager

func NewPowerManager() *PowerManager

implements desired state reconciliation for controlling device's power

func (*PowerManager) CommitDiff

func (p *PowerManager) CommitDiff(pd PowerDiff)

marks diff as "committed" so it won't show up as diff the next time

func (*PowerManager) Diff

func (p *PowerManager) Diff() []PowerDiff

func (*PowerManager) GetActual

func (p *PowerManager) GetActual(deviceId string) bool

func (*PowerManager) Register

func (p *PowerManager) Register(deviceId string, isOn bool)

func (*PowerManager) Set

func (p *PowerManager) Set(deviceId string, power PowerKind)

func (*PowerManager) SetBypassingDiffs

func (p *PowerManager) SetBypassingDiffs(deviceId string, power PowerKind)

just set actual state to something without triggering a diff that would send a message. one case for wanting this is sending brightness msg which will implicitly turn the bulb on even though we didn't send an explicit power message

func (*PowerManager) SetExplicit

func (p *PowerManager) SetExplicit(deviceId string, power PowerKind)

type PowerMsg

type PowerMsg struct {
	DeviceId     string
	PowerCommand string
	On           bool
}

func NewPowerMsg

func NewPowerMsg(deviceId string, powerCommand string, on bool) *PowerMsg

func (*PowerMsg) OutboundEventType

func (e *PowerMsg) OutboundEventType() string

func (*PowerMsg) RedirectInbound

func (e *PowerMsg) RedirectInbound(toDeviceId string) InboundEvent

used by device group adapter, therefore we can mark these as implicit

type PresenceByPingDevice

type PresenceByPingDevice struct {
	Ip     string `json:"ip"`
	Person string `json:"person"`
}

type PublishEvent

type PublishEvent struct {
	Topic string
}

func NewPublishEvent

func NewPublishEvent(topic string) *PublishEvent

func (*PublishEvent) InboundEventType

func (e *PublishEvent) InboundEventType() string

type PushButtonEvent

type PushButtonEvent struct {
	Device    string
	Specifier string // single/double/...
}

func NewPushButtonEvent

func NewPushButtonEvent(deviceId string, specifier string) *PushButtonEvent

func (*PushButtonEvent) InboundEventType

func (e *PushButtonEvent) InboundEventType() string

type RGB

type RGB struct {
	Red   uint8
	Green uint8
	Blue  uint8
}

func NewRGB

func NewRGB(red, green, blue uint8) RGB

func (RGB) IsGrayscale

func (r RGB) IsGrayscale() bool

type RawInfraredEvent

type RawInfraredEvent struct {
	Remote string
	Event  string
}

func NewRawInfraredEvent

func NewRawInfraredEvent(remote string, event string) *RawInfraredEvent

func (*RawInfraredEvent) InboundEventType

func (e *RawInfraredEvent) InboundEventType() string

type SpeakEvent

type SpeakEvent struct {
	Device  string
	Message string
}

func NewSpeakEvent

func NewSpeakEvent(deviceId string, message string) *SpeakEvent

func (*SpeakEvent) InboundEventType

func (e *SpeakEvent) InboundEventType() string

type Statefile

type Statefile struct {
	Devices map[string]DeviceStateSnapshot `json:"device_state_snapshots_by_id"`
}

func NewStatefile

func NewStatefile() Statefile

type SubscribeConfig

type SubscribeConfig struct {
	Event      string            `json:"event"`
	Actions    []ActionConfig    `json:"action"`
	Conditions []ConditionConfig `json:"condition"`
}

type TemperatureHumidityPressureEvent

type TemperatureHumidityPressureEvent struct {
	Device      string
	Temperature float64
	Humidity    float64
	Pressure    float64
}

func NewTemperatureHumidityPressureEvent

func NewTemperatureHumidityPressureEvent(
	deviceId string,
	temperature float64,
	humidity float64,
	pressure float64,
) *TemperatureHumidityPressureEvent

func (*TemperatureHumidityPressureEvent) InboundEventType

func (e *TemperatureHumidityPressureEvent) InboundEventType() string

type UrlChangeDetector

type UrlChangeDetector struct {
	Id  string `json:"id"`
	Url string `json:"url"`
}

type VibrationEvent

type VibrationEvent struct {
	Device string
}

func NewVibrationEvent

func NewVibrationEvent(deviceId string) *VibrationEvent

func (*VibrationEvent) InboundEventType

func (e *VibrationEvent) InboundEventType() string

type WaterLeakEvent

type WaterLeakEvent struct {
	Device        string
	WaterDetected bool
}

func NewWaterLeakEvent

func NewWaterLeakEvent(deviceId string, waterDetected bool) *WaterLeakEvent

func (*WaterLeakEvent) InboundEventType

func (e *WaterLeakEvent) InboundEventType() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL