Skip to content

Commit ed4345f

Browse files
author
Paul Richards
committed
Fix PTZ: use async/await pattern matching working framing-assistant
1 parent dbe0d85 commit ed4345f

File tree

2 files changed

+115
-60
lines changed

2 files changed

+115
-60
lines changed

14-tracking-comparison/app.js

Lines changed: 60 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -193,26 +193,39 @@ document.addEventListener('DOMContentLoaded', async function() {
193193
startCamera(cameraSelect.value);
194194
});
195195

196-
testConnectionBtn.addEventListener('click', () => {
196+
testConnectionBtn.addEventListener('click', async () => {
197197
const ip = cameraIPInput.value.trim();
198198
if (!ip) {
199199
updateStatus('Enter camera IP first', true);
200200
return;
201201
}
202202
saveSettings();
203203
console.log('Creating PTZ controller for IP:', ip);
204+
204205
ptzController = new PTZController(ip, {
205206
useAuth: useAuthCheckbox.checked,
206207
username: authUsernameInput.value,
207208
password: authPasswordInput.value
208209
});
209210
ptzController.setDeadzone(parseInt(deadzoneSlider.value));
210-
console.log('PTZ controller created, sending stop command...');
211-
ptzController.stop();
212-
connectionStatus.textContent = 'Connected';
213-
connectionStatus.classList.remove('disconnected');
214-
connectionStatus.classList.add('connected');
215-
updateStatus('PTZ connected');
211+
212+
connectionStatus.textContent = 'Testing...';
213+
testConnectionBtn.disabled = true;
214+
215+
try {
216+
await ptzController.stop();
217+
connectionStatus.textContent = 'Connected';
218+
connectionStatus.classList.remove('disconnected');
219+
connectionStatus.classList.add('connected');
220+
updateStatus('PTZ connected');
221+
} catch (e) {
222+
connectionStatus.textContent = 'Failed';
223+
connectionStatus.classList.remove('connected');
224+
connectionStatus.classList.add('disconnected');
225+
updateStatus('PTZ connection failed', true);
226+
} finally {
227+
testConnectionBtn.disabled = false;
228+
}
216229
});
217230

218231
useAuthCheckbox.addEventListener('change', () => {
@@ -229,26 +242,47 @@ document.addEventListener('DOMContentLoaded', async function() {
229242
startBtn.addEventListener('click', startTracking);
230243
stopBtn.addEventListener('click', stopTracking);
231244

232-
document.querySelectorAll('[data-ptz]').forEach(btn => {
233-
const cmd = btn.dataset.ptz;
234-
btn.addEventListener('mousedown', () => {
235-
console.log('PTZ button pressed:', cmd, 'controller:', !!ptzController);
236-
if (!ptzController) {
237-
console.log('No PTZ controller! Click Test first.');
238-
return;
245+
async function handleManualPTZ(command) {
246+
if (!ptzController) {
247+
console.log('No PTZ controller! Click Test first.');
248+
updateStatus('Connect PTZ camera first', true);
249+
return;
250+
}
251+
console.log('PTZ manual:', command);
252+
253+
try {
254+
switch (command) {
255+
case 'up':
256+
await ptzController.tiltUp();
257+
await ptzController.delay(200);
258+
await ptzController.stop();
259+
break;
260+
case 'down':
261+
await ptzController.tiltDown();
262+
await ptzController.delay(200);
263+
await ptzController.stop();
264+
break;
265+
case 'left':
266+
await ptzController.panLeft();
267+
await ptzController.delay(200);
268+
await ptzController.stop();
269+
break;
270+
case 'right':
271+
await ptzController.panRight();
272+
await ptzController.delay(200);
273+
await ptzController.stop();
274+
break;
275+
case 'stop':
276+
await ptzController.stop();
277+
break;
239278
}
240-
if (cmd === 'up') ptzController.tiltUp();
241-
else if (cmd === 'down') ptzController.tiltDown();
242-
else if (cmd === 'left') ptzController.panLeft();
243-
else if (cmd === 'right') ptzController.panRight();
244-
else if (cmd === 'stop') ptzController.stop();
245-
});
246-
btn.addEventListener('mouseup', () => {
247-
if (ptzController && cmd !== 'stop') ptzController.stop();
248-
});
249-
btn.addEventListener('mouseleave', () => {
250-
if (ptzController && cmd !== 'stop') ptzController.stop();
251-
});
279+
} catch (e) {
280+
console.error('PTZ error:', e);
281+
}
282+
}
283+
284+
document.querySelectorAll('[data-ptz]').forEach(btn => {
285+
btn.addEventListener('click', () => handleManualPTZ(btn.dataset.ptz));
252286
});
253287

254288
async function startTracking() {

14-tracking-comparison/ptz-controller.js

Lines changed: 55 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ class PTZController {
66
this.username = options.username || '';
77
this.password = options.password || '';
88
this.deadzone = 10;
9-
this.speed = { pan: 5, tilt: 5, zoom: 5 };
9+
this.speed = { pan: 8, tilt: 8, zoom: 5 };
1010
this.moveCount = 0;
1111
this.lastMoveTime = 0;
12-
this.moveCooldown = 200;
12+
this.moveCooldown = 300;
1313
}
1414

1515
setAuth(useAuth, username = '', password = '') {
@@ -30,10 +30,10 @@ class PTZController {
3030
this.speed = { ...this.speed, ...speed };
3131
}
3232

33-
sendCommand(command) {
33+
async sendCommand(command) {
3434
if (!this.cameraIP) {
3535
console.log('PTZ: No camera IP set');
36-
return;
36+
return false;
3737
}
3838

3939
const url = `http://${this.cameraIP}/cgi-bin/ptzctrl.cgi?${command}`;
@@ -45,54 +45,63 @@ class PTZController {
4545
opts.headers = { 'Authorization': 'Basic ' + btoa(this.username + ':' + this.password) };
4646
}
4747

48-
fetch(url, opts)
49-
.then(() => console.log('PTZ: Command sent'))
50-
.catch(err => console.error('PTZ: Fetch error', err));
48+
try {
49+
await fetch(url, opts);
50+
console.log('PTZ: Command sent');
51+
return true;
52+
} catch (err) {
53+
console.error('PTZ: Fetch error', err);
54+
return false;
55+
}
5156
}
5257

53-
stop() {
58+
delay(ms) {
59+
return new Promise(resolve => setTimeout(resolve, ms));
60+
}
61+
62+
async stop() {
5463
this.isMoving = false;
55-
this.sendCommand('ptzcmd&ptzstop');
64+
return this.sendCommand('ptzcmd&ptzstop');
5665
}
5766

58-
panRight() {
67+
async panRight() {
5968
this.isMoving = true;
60-
this.sendCommand(`ptzcmd&right&${this.speed.pan}&${this.speed.pan}`);
69+
return this.sendCommand(`ptzcmd&right&${this.speed.pan}&${this.speed.pan}`);
6170
}
6271

63-
panLeft() {
72+
async panLeft() {
6473
this.isMoving = true;
65-
this.sendCommand(`ptzcmd&left&${this.speed.pan}&${this.speed.pan}`);
74+
return this.sendCommand(`ptzcmd&left&${this.speed.pan}&${this.speed.pan}`);
6675
}
6776

68-
tiltDown() {
77+
async tiltDown() {
6978
this.isMoving = true;
70-
this.sendCommand(`ptzcmd&down&${this.speed.tilt}&${this.speed.tilt}`);
79+
return this.sendCommand(`ptzcmd&down&${this.speed.tilt}&${this.speed.tilt}`);
7180
}
7281

73-
tiltUp() {
82+
async tiltUp() {
7483
this.isMoving = true;
75-
this.sendCommand(`ptzcmd&up&${this.speed.tilt}&${this.speed.tilt}`);
84+
return this.sendCommand(`ptzcmd&up&${this.speed.tilt}&${this.speed.tilt}`);
7685
}
7786

78-
zoomIn() {
87+
async zoomIn() {
7988
this.isMoving = true;
80-
this.sendCommand(`ptzcmd&zoomin&${this.speed.zoom}`);
89+
return this.sendCommand(`ptzcmd&zoomin&${this.speed.zoom}`);
8190
}
8291

83-
zoomOut() {
92+
async zoomOut() {
8493
this.isMoving = true;
85-
this.sendCommand(`ptzcmd&zoomout&${this.speed.zoom}`);
94+
return this.sendCommand(`ptzcmd&zoomout&${this.speed.zoom}`);
8695
}
8796

88-
home() {
97+
async home() {
8998
this.isMoving = false;
90-
this.sendCommand('ptzcmd&home');
99+
return this.sendCommand('ptzcmd&home');
91100
}
92101

93-
trackObject(detection) {
102+
async trackObject(detection) {
94103
if (!detection) {
95-
if (this.isMoving) this.stop();
104+
if (this.isMoving) await this.stop();
96105
return false;
97106
}
98107

@@ -105,27 +114,37 @@ class PTZController {
105114
const offsetY = (detection.y * 100) - 50;
106115
const threshold = this.deadzone / 2;
107116

108-
console.log(`PTZ: x=${detection.x.toFixed(2)} y=${detection.y.toFixed(2)} offsetX=${offsetX.toFixed(1)} offsetY=${offsetY.toFixed(1)} threshold=${threshold}`);
117+
console.log(`PTZ Track: x=${detection.x.toFixed(2)} offsetX=${offsetX.toFixed(1)} threshold=${threshold}`);
109118

110119
if (Math.abs(offsetX) <= threshold && Math.abs(offsetY) <= threshold) {
111-
if (this.isMoving) this.stop();
120+
if (this.isMoving) await this.stop();
112121
return false;
113122
}
114123

115124
this.lastMoveTime = now;
116-
let cmd = '';
117125

118126
if (Math.abs(offsetX) > Math.abs(offsetY)) {
119-
if (offsetX > threshold) { this.panRight(); cmd = 'panRight'; }
120-
else if (offsetX < -threshold) { this.panLeft(); cmd = 'panLeft'; }
127+
if (offsetX > threshold) {
128+
console.log('PTZ: Pan Right');
129+
await this.panRight();
130+
} else if (offsetX < -threshold) {
131+
console.log('PTZ: Pan Left');
132+
await this.panLeft();
133+
}
121134
} else {
122-
if (offsetY > threshold) { this.tiltDown(); cmd = 'tiltDown'; }
123-
else if (offsetY < -threshold) { this.tiltUp(); cmd = 'tiltUp'; }
135+
if (offsetY > threshold) {
136+
console.log('PTZ: Tilt Down');
137+
await this.tiltDown();
138+
} else if (offsetY < -threshold) {
139+
console.log('PTZ: Tilt Up');
140+
await this.tiltUp();
141+
}
124142
}
125143

126-
console.log(`PTZ: Sending ${cmd}`);
144+
await this.delay(200);
145+
await this.stop();
146+
127147
this.moveCount++;
128-
setTimeout(() => this.stop(), 150);
129148
return true;
130149
}
131150

@@ -137,3 +156,5 @@ class PTZController {
137156
this.moveCount = 0;
138157
}
139158
}
159+
160+
window.PTZController = PTZController;

0 commit comments

Comments
 (0)